Index: openafs/src/WINNT/afsd/afsd_eventmessages.mc
diff -c openafs/src/WINNT/afsd/afsd_eventmessages.mc:1.4 openafs/src/WINNT/afsd/afsd_eventmessages.mc:1.4.4.2
*** openafs/src/WINNT/afsd/afsd_eventmessages.mc:1.4	Sun Jan 15 21:05:27 2006
--- openafs/src/WINNT/afsd/afsd_eventmessages.mc	Thu Sep 11 13:26:21 2008
***************
*** 114,120 ****
  Facility=System
  SymbolicName=MSG_SERVER_REPORTS_VNOVOL
  Language=English
! Server %1 reported volume %2 as not attached.
  .
  
  MessageId=
--- 114,120 ----
  Facility=System
  SymbolicName=MSG_SERVER_REPORTS_VNOVOL
  Language=English
! Server %1 reported volume %2 as not attached (may have been moved or deleted).
  .
  
  MessageId=
***************
*** 326,331 ****
--- 326,340 ----
  MessageId=
  Severity=Informational
  Facility=System
+ SymbolicName=MSG_CRYPT_AUTH
+ Language=English
+ Security Level is Auth (Integrity Only).
+ .
+ 
+ 
+ MessageId=
+ Severity=Informational
+ Facility=System
  SymbolicName=MSG_CRYPT_ON
  Language=English
  Security Level is Crypt.
Index: openafs/src/WINNT/afsd/afsd_init.c
diff -c openafs/src/WINNT/afsd/afsd_init.c:1.79.2.46 openafs/src/WINNT/afsd/afsd_init.c:1.79.2.52
*** openafs/src/WINNT/afsd/afsd_init.c:1.79.2.46	Sat Aug 16 13:11:01 2008
--- openafs/src/WINNT/afsd/afsd_init.c	Fri Sep 12 10:41:30 2008
***************
*** 561,566 ****
--- 561,567 ----
      DWORD rx_enable_peer_stats;
      DWORD rx_enable_process_stats;
      DWORD rx_udpbufsize = -1;
+     DWORD lockOrderValidation;
      long traceBufSize;
      long maxcpus;
      long ltt, ltto;
***************
*** 625,630 ****
--- 626,644 ----
          osi_panic(buf, __FILE__, __LINE__);
      }
  
+     dummyLen = sizeof(lockOrderValidation);
+     code = RegQueryValueEx(parmKey, "LockOrderValidation", NULL, NULL,
+                             (BYTE *) &lockOrderValidation, &dummyLen);
+     if (code != ERROR_SUCCESS) {
+ #ifdef DEBUG
+         lockOrderValidation = 1;
+ #else
+         lockOrderValidation = 0;
+ #endif
+     }
+     osi_SetLockOrderValidation(lockOrderValidation);
+     afsi_log("Lock Order Validation %s", lockOrderValidation ? "On" : "Off");
+ 
      dummyLen = sizeof(maxcpus);
      code = RegQueryValueEx(parmKey, "MaxCPUs", NULL, NULL,
                              (BYTE *) &maxcpus, &dummyLen);
***************
*** 956,969 ****
      code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
                             (BYTE *) &cryptall, &dummyLen);
      if (code == ERROR_SUCCESS) {
!         afsi_log("SecurityLevel is %s", cryptall?"crypt":"clear");
      } else {
          cryptall = 0;
          afsi_log("Default SecurityLevel is clear");
      }
  
!     if (cryptall)
  	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
      else
  	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
  
--- 970,985 ----
      code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
                             (BYTE *) &cryptall, &dummyLen);
      if (code == ERROR_SUCCESS) {
!         afsi_log("SecurityLevel is %s", cryptall == 1?"crypt": cryptall == 2?"auth":"clear");
      } else {
          cryptall = 0;
          afsi_log("Default SecurityLevel is clear");
      }
  
!     if (cryptall == 1)
  	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
+     else if (cryptall == 2)
+ 	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_AUTH);
      else
  	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
  
***************
*** 1049,1058 ****
      code = RegQueryValueEx(parmKey, "RxNoJumbo", NULL, NULL,
                             (BYTE *) &rx_nojumbo, &dummyLen);
      if (code != ERROR_SUCCESS) {
!         rx_nojumbo = 0;
      }
      if (rx_nojumbo)
          afsi_log("RX Jumbograms are disabled");
  
      dummyLen = sizeof(rx_extraPackets);
      code = RegQueryValueEx(parmKey, "RxExtraPackets", NULL, NULL,
--- 1065,1084 ----
      code = RegQueryValueEx(parmKey, "RxNoJumbo", NULL, NULL,
                             (BYTE *) &rx_nojumbo, &dummyLen);
      if (code != ERROR_SUCCESS) {
!         DWORD jumbo;
!         dummyLen = sizeof(jumbo);
!         code = RegQueryValueEx(parmKey, "RxJumbo", NULL, NULL,
!                                 (BYTE *) &jumbo, &dummyLen);
!         if (code != ERROR_SUCCESS) {
!             rx_nojumbo = 1;
!         } else {
!             rx_nojumbo = !jumbo;
!         }
      }
      if (rx_nojumbo)
          afsi_log("RX Jumbograms are disabled");
+     else
+         afsi_log("RX Jumbograms are enabled");
  
      dummyLen = sizeof(rx_extraPackets);
      code = RegQueryValueEx(parmKey, "RxExtraPackets", NULL, NULL,
***************
*** 1069,1075 ****
      if (code != ERROR_SUCCESS) {
          rx_udpbufsize = 256*1024;
      }
!     if (rx_udpbufsize)
          afsi_log("RX udpbufsize is %d", rx_udpbufsize);
  
      dummyLen = sizeof(rx_mtu);
--- 1095,1101 ----
      if (code != ERROR_SUCCESS) {
          rx_udpbufsize = 256*1024;
      }
!     if (rx_udpbufsize != -1)
          afsi_log("RX udpbufsize is %d", rx_udpbufsize);
  
      dummyLen = sizeof(rx_mtu);
***************
*** 1324,1329 ****
--- 1350,1358 ----
          *reasonP = "unknown error";
          return -1;
      }
+     rx_SetMinProcs(serverp, 2);
+     rx_SetMaxProcs(serverp, 4);
+     rx_SetCheckReach(serverp, 1);
  
      nullServerSecurityClassp = rxnull_NewServerSecurityObject();
      serverp = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats",
***************
*** 1333,1338 ****
--- 1362,1369 ----
          *reasonP = "unknown error";
          return -1;
      }
+     rx_SetMinProcs(serverp, 2);
+     rx_SetMaxProcs(serverp, 4);
          
      /* start server threads, *not* donating this one to the pool */
      rx_StartServer(0);
***************
*** 1683,1690 ****
  void 
  GenerateMiniDump(PEXCEPTION_POINTERS ep)
  {
! 	if (IsDebuggerPresent())
! 		return;
  
      if (ep == NULL) 
      {
--- 1714,1721 ----
  void 
  GenerateMiniDump(PEXCEPTION_POINTERS ep)
  {
!     if (IsDebuggerPresent())
!         return;
  
      if (ep == NULL) 
      {
Index: openafs/src/WINNT/afsd/afsd_service.c
diff -c openafs/src/WINNT/afsd/afsd_service.c:1.52.4.27 openafs/src/WINNT/afsd/afsd_service.c:1.52.4.30
*** openafs/src/WINNT/afsd/afsd_service.c:1.52.4.27	Fri Aug  1 15:13:51 2008
--- openafs/src/WINNT/afsd/afsd_service.c	Fri Aug 29 22:06:28 2008
***************
*** 34,39 ****
--- 34,40 ----
  
  static SERVICE_STATUS		ServiceStatus;
  static SERVICE_STATUS_HANDLE	StatusHandle;
+ static BOOL bRunningAsService = TRUE;
  
  HANDLE hAFSDMainThread = NULL;
  
***************
*** 52,62 ****
--- 53,67 ----
  static int powerEventsRegistered = 0;
  extern int powerStateSuspended = 0;
  
+ static VOID (WINAPI* pRtlCaptureContext)(PCONTEXT ContextRecord) = NULL;
+ 
  /*
   * Notifier function for use by osi_panic
   */
  static void afsd_notifier(char *msgp, char *filep, long line)
  {
+     CONTEXT context;
+ 
      if (!msgp)
          msgp = "unspecified assert";
  
***************
*** 73,87 ****
      afsd_ForceTrace(TRUE);
      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");
- #endif
      cm_DumpBufHashTable(afsi_file, "a", 0);
      smb_DumpVCP(afsi_file, "a", 0);			
      afsi_log("--- end   dump ---");
--- 78,94 ----
      afsd_ForceTrace(TRUE);
      buf_ForceTrace(TRUE);
  
+     if (pRtlCaptureContext) {
+         pRtlCaptureContext(&context);
+         afsd_printStack(GetCurrentThread(), &context);
+     }
+ 
      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);
      cm_DumpBufHashTable(afsi_file, "a", 0);
      smb_DumpVCP(afsi_file, "a", 0);			
      afsi_log("--- end   dump ---");
***************
*** 91,96 ****
--- 98,105 ----
          DebugBreak();	
  #endif
  
+     GenerateMiniDump(NULL);
+ 
      SetEvent(WaitToTerminate);
  
  #ifdef JUMP
***************
*** 98,110 ****
          longjmp(notifier_jmp, 1);
  #endif /* JUMP */
  
!     ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!     ServiceStatus.dwWin32ExitCode = NO_ERROR;
!     ServiceStatus.dwCheckPoint = 0;
!     ServiceStatus.dwWaitHint = 0;
!     ServiceStatus.dwControlsAccepted = 0;
!     SetServiceStatus(StatusHandle, &ServiceStatus);
! 
      exit(1);
  }
  
--- 107,120 ----
          longjmp(notifier_jmp, 1);
  #endif /* JUMP */
  
!     if (bRunningAsService) {
!         ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 0;
!         ServiceStatus.dwWaitHint = 0;
!         ServiceStatus.dwControlsAccepted = 0;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
!     }
      exit(1);
  }
  
***************
*** 1095,1100 ****
--- 1105,1111 ----
  #endif /* JUMP */
      HMODULE hHookDll;
      HMODULE hAdvApi32;
+     HMODULE hKernel32;
  
  #ifdef _DEBUG
      void afsd_DbgBreakAllocInit();
***************
*** 1109,1114 ****
--- 1120,1133 ----
      osi_InitPanic(afsd_notifier);
      osi_InitTraceOption();
  
+     hKernel32 = LoadLibrary("kernel32.dll");
+     if (hKernel32 == NULL)
+     {
+         afsi_log("Fatal: cannot load kernel32.dll");
+         return;
+     }
+     pRtlCaptureContext = GetProcAddress(hKernel32, "RtlCaptureContext");
+ 
      GlobalStatus = 0;
  
      afsi_start();
***************
*** 1125,1150 ****
          return;
      }
  
!     pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
!     if (pRegisterServiceCtrlHandlerEx)
!     {
!         afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
!         StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
!     }
!     else
!     {
!         StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
!     }
  
!     ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
!     ServiceStatus.dwServiceSpecificExitCode = 0;
!     ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
!     ServiceStatus.dwWin32ExitCode = NO_ERROR;
!     ServiceStatus.dwCheckPoint = 1;
!     ServiceStatus.dwWaitHint = 120000;
!     /* accept Power Events */
!     ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
!     SetServiceStatus(StatusHandle, &ServiceStatus);
  #endif
  
      LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
--- 1144,1171 ----
          return;
      }
  
!     if (bRunningAsService) {
!         pRegisterServiceCtrlHandlerEx = (RegisterServiceCtrlHandlerExFunc)GetProcAddress(hAdvApi32, "RegisterServiceCtrlHandlerExA");
!         if (pRegisterServiceCtrlHandlerEx)
!         {
!             afsi_log("running on 2000+ - using RegisterServiceCtrlHandlerEx");
!             StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandlerEx, NULL );
!         }
!         else
!         {
!             StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME, afsd_ServiceControlHandler);
!         }
  
!         ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
!         ServiceStatus.dwServiceSpecificExitCode = 0;
!         ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 1;
!         ServiceStatus.dwWaitHint = 120000;
!         /* accept Power Events */
!         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
!     }
  #endif
  
      LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_START_PENDING);
***************
*** 1179,1191 ****
  
      /* Verify the versions of the DLLs which were loaded */
      if (!AFSModulesVerify()) {
!         ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 0;
!         ServiceStatus.dwWaitHint = 0;
!         ServiceStatus.dwControlsAccepted = 0;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
! 
  	LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
  
          /* exit if initialization failed */
--- 1200,1213 ----
  
      /* Verify the versions of the DLLs which were loaded */
      if (!AFSModulesVerify()) {
!         if (bRunningAsService) {
!             ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!             ServiceStatus.dwWin32ExitCode = NO_ERROR;
!             ServiceStatus.dwCheckPoint = 0;
!             ServiceStatus.dwWaitHint = 0;
!             ServiceStatus.dwControlsAccepted = 0;
!             SetServiceStatus(StatusHandle, &ServiceStatus);
!         }
  	LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_INCORRECT_VERSIONS);
  
          /* exit if initialization failed */
***************
*** 1207,1234 ****
  
          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;
          }
          else
          {
              /* 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 = 120000;
!             /* accept Power Events */
!             ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
!             SetServiceStatus(StatusHandle, &ServiceStatus);
          }
      }
  
--- 1229,1259 ----
  
          if (hookRc == FALSE)
          {
!             if (bRunningAsService) {
!                 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;
          }
          else
          {
              /* allow another 120 seconds to start */
!             if (bRunningAsService) {
!                 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
!                 ServiceStatus.dwServiceSpecificExitCode = 0;
!                 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
!                 ServiceStatus.dwWin32ExitCode = NO_ERROR;
!                 ServiceStatus.dwCheckPoint = 2;
!                 ServiceStatus.dwWaitHint = 120000;
!                 /* accept Power Events */
!                 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
!                 SetServiceStatus(StatusHandle, &ServiceStatus);
!             }
          }
      }
  
***************
*** 1249,1257 ****
          }
  
  #ifndef NOTSERVICE
!         ServiceStatus.dwCheckPoint = 3;
!         ServiceStatus.dwWaitHint = 30000;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
  #endif
          code = afsd_InitDaemons(&reason);
          if (code != 0) {
--- 1274,1284 ----
          }
  
  #ifndef NOTSERVICE
!         if (bRunningAsService) {
!             ServiceStatus.dwCheckPoint = 3;
!             ServiceStatus.dwWaitHint = 30000;
!             SetServiceStatus(StatusHandle, &ServiceStatus);
!         }
  #endif
          code = afsd_InitDaemons(&reason);
          if (code != 0) {
***************
*** 1274,1295 ****
  
              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;
              }
          }
  
  #ifndef NOTSERVICE
!         ServiceStatus.dwCheckPoint = 4;
!         ServiceStatus.dwWaitHint = 15000;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
  #endif
  
          /* Notify any volume status handlers that the cache manager has started */
--- 1301,1325 ----
  
              if (hookRc == FALSE)
              {
!                 if (bRunningAsService) {
!                     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;
              }
          }
  
  #ifndef NOTSERVICE
!         if (bRunningAsService) {
!             ServiceStatus.dwCheckPoint = 4;
!             ServiceStatus.dwWaitHint = 15000;
!             SetServiceStatus(StatusHandle, &ServiceStatus);
!         }
  #endif
  
          /* Notify any volume status handlers that the cache manager has started */
***************
*** 1319,1331 ****
  
              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;
              }
--- 1349,1362 ----
  
              if (hookRc == FALSE)
              {
!                 if (bRunningAsService) {
!                     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;
              }
***************
*** 1334,1347 ****
          MountGlobalDrives();
  
  #ifndef NOTSERVICE
!         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
!         ServiceStatus.dwWin32ExitCode = NO_ERROR;
!         ServiceStatus.dwCheckPoint = 5;
!         ServiceStatus.dwWaitHint = 0;
  
!         /* accept Power events */
!         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
  #endif  
  
  	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
--- 1365,1380 ----
          MountGlobalDrives();
  
  #ifndef NOTSERVICE
!         if (bRunningAsService) {
!             ServiceStatus.dwCurrentState = SERVICE_RUNNING;
!             ServiceStatus.dwWin32ExitCode = NO_ERROR;
!             ServiceStatus.dwCheckPoint = 5;
!             ServiceStatus.dwWaitHint = 0;
  
!             /* accept Power events */
!             ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
!             SetServiceStatus(StatusHandle, &ServiceStatus);
!         }
  #endif  
  
  	LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVICE_RUNNING);
***************
*** 1362,1374 ****
  
          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;
          }
--- 1395,1408 ----
  
          if (hookRc == FALSE)
          {
!             if (bRunningAsService) {
!                 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;
          }
***************
*** 1376,1388 ****
  
      WaitForSingleObject(WaitToTerminate, INFINITE);
  
!     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 )
--- 1410,1423 ----
  
      WaitForSingleObject(WaitToTerminate, INFINITE);
  
!     if (bRunningAsService) {
!         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 )
***************
*** 1413,1426 ****
      DismountGlobalDrives();
      afsi_log("Global Drives dismounted");
                                           
-     cm_DaemonShutdown();                 
-     afsi_log("Daemon shutdown complete");
-     
-     afsd_ShutdownCM();
- 
-     buf_Shutdown();                      
-     afsi_log("Buffer shutdown complete");
-                                          
      smb_Shutdown();                      
      afsi_log("smb shutdown complete");   
                                           
--- 1448,1453 ----
***************
*** 1428,1433 ****
--- 1455,1468 ----
  
      cm_ReleaseAllLocks();
  
+     cm_DaemonShutdown();                 
+     afsi_log("Daemon shutdown complete");
+     
+     buf_Shutdown();                      
+     afsi_log("Buffer shutdown complete");
+                                          
+     afsd_ShutdownCM();
+ 
      cm_ShutdownMappedMemory();           
  
      rx_Finalize();
***************
*** 1467,1478 ****
      /* Remove the ExceptionFilter */
      SetUnhandledExceptionFilter(NULL);
  
!     ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!     ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
!     ServiceStatus.dwCheckPoint = 7;
!     ServiceStatus.dwWaitHint = 0;
!     ServiceStatus.dwControlsAccepted = 0;
!     SetServiceStatus(StatusHandle, &ServiceStatus);
  }       
  
  DWORD __stdcall afsdMain_thread(void* notUsed)
--- 1502,1515 ----
      /* Remove the ExceptionFilter */
      SetUnhandledExceptionFilter(NULL);
  
!     if (bRunningAsService) {
!         ServiceStatus.dwCurrentState = SERVICE_STOPPED;
!         ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
!         ServiceStatus.dwCheckPoint = 7;
!         ServiceStatus.dwWaitHint = 0;
!         ServiceStatus.dwControlsAccepted = 0;
!         SetServiceStatus(StatusHandle, &ServiceStatus);
!     }
  }       
  
  DWORD __stdcall afsdMain_thread(void* notUsed)
***************
*** 1516,1521 ****
--- 1553,1561 ----
          if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
          {
              DWORD tid;
+ 
+             bRunningAsService = FALSE;
+ 
              hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
  		
              printf("Hit <Enter> to terminate OpenAFS Client Service\n");
Index: openafs/src/WINNT/afsd/cm.h
diff -c openafs/src/WINNT/afsd/cm.h:1.17.2.15 openafs/src/WINNT/afsd/cm.h:1.17.2.17
*** openafs/src/WINNT/afsd/cm.h:1.17.2.15	Mon Jul 28 19:05:32 2008
--- openafs/src/WINNT/afsd/cm.h	Tue Sep 16 07:47:47 2008
***************
*** 99,108 ****
--- 99,154 ----
  #define CM_ERROR_RANGE_NOT_LOCKED       (CM_ERROR_BASE+57)
  #define CM_ERROR_NOSUCHDEVICE           (CM_ERROR_BASE+58)
  #define CM_ERROR_LOCK_NOT_GRANTED       (CM_ERROR_BASE+59)
+ #define CM_ERROR_NOTINCACHE             (CM_ERROR_BASE+60)
  
  /* Used by cm_FollowMountPoint and cm_FindVolumeByName */
  /* And as an index in cm_volume_t */
  #define RWVOL	0
  #define ROVOL	1
  #define BACKVOL	2
+ 
+ #define LOCK_HIERARCHY_IGNORE                    0
+ 
+ #define LOCK_HIERARCHY_SMB_STARTED              30
+ #define LOCK_HIERARCHY_SMB_LISTENER             35
+ #define LOCK_HIERARCHY_SMB_GLOBAL               40
+ #define LOCK_HIERARCHY_SMB_DIRSEARCH            50
+ #define LOCK_HIERARCHY_SMB_FID                  60
+ #define LOCK_HIERARCHY_SMB_TID                  70
+ #define LOCK_HIERARCHY_SMB_UID                  80
+ #define LOCK_HIERARCHY_SMB_RAWBUF              100
+ #define LOCK_HIERARCHY_SMB_DIRWATCH            105
+ #define LOCK_HIERARCHY_SMB_RCT_GLOBAL          110
+ #define LOCK_HIERARCHY_SMB_USERNAME            115
+ #define LOCK_HIERARCHY_SMB_VC                  120
+ 
+ 
+ #define LOCK_HIERARCHY_DAEMON_GLOBAL           400
+ 
+ #define LOCK_HIERARCHY_SCACHE_DIRLOCK          500
+ #define LOCK_HIERARCHY_SCACHE_BUFCREATE        510
+ #define LOCK_HIERARCHY_BUFFER                  530
+ #define LOCK_HIERARCHY_SCACHE                  540
+ #define LOCK_HIERARCHY_BUF_GLOBAL              550
+ #define LOCK_HIERARCHY_VOLUME                  560
+ #define LOCK_HIERARCHY_USER                    570
+ #define LOCK_HIERARCHY_SCACHE_GLOBAL           580
+ #define LOCK_HIERARCHY_CONN_GLOBAL             600
+ #define LOCK_HIERARCHY_CELL                    620
+ #define LOCK_HIERARCHY_CELL_GLOBAL             630
+ #define LOCK_HIERARCHY_SERVER                  640
+ #define LOCK_HIERARCHY_CALLBACK_GLOBAL         645
+ #define LOCK_HIERARCHY_SERVER_GLOBAL           650
+ #define LOCK_HIERARCHY_CONN                    660 
+ #define LOCK_HIERARCHY_VOLUME_GLOBAL           670
+ #define LOCK_HIERARCHY_DNLC_GLOBAL             690
+ #define LOCK_HIERARCHY_FREELANCE_GLOBAL        700
+ #define LOCK_HIERARCHY_UTILS_GLOBAL            710
+ #define LOCK_HIERARCHY_OTHER_GLOBAL            720
+ #define LOCK_HIERARCHY_ACL_GLOBAL              730
+ #define LOCK_HIERARCHY_USER_GLOBAL             740
+ #define LOCK_HIERARCHY_AFSDBSBMT_GLOBAL       1000
+ #define LOCK_HIERARCHY_TOKEN_EVENT_GLOBAL     2000
+ #define LOCK_HIERARCHY_SYSCFG_GLOBAL          3000
  #endif /*  __CM_H_ENV__ */
+ 
Index: openafs/src/WINNT/afsd/cm_access.c
diff -c openafs/src/WINNT/afsd/cm_access.c:1.7.2.21 openafs/src/WINNT/afsd/cm_access.c:1.7.2.22
*** openafs/src/WINNT/afsd/cm_access.c:1.7.2.21	Tue Aug  5 11:46:37 2008
--- openafs/src/WINNT/afsd/cm_access.c	Fri Aug 22 14:10:00 2008
***************
*** 39,50 ****
      long trights;
      int release = 0;    /* Used to avoid a call to cm_HoldSCache in the directory case */
  
- #if 0
-     if (scp->flags & CM_SCACHEFLAG_EACCESS) {
-     	*outRightsp = 0;
- 	return 1;
-     }
- #endif
      didLock = 0;
      if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
          aclScp = scp;   /* not held, not released */
--- 39,44 ----
***************
*** 54,65 ****
          if (!aclScp) 
              return 0;
          if (aclScp != scp) {
!             code = lock_TryRead(&aclScp->rw);
!             if (code == 0) {
!                 /* can't get lock safely and easily */
!                 cm_ReleaseSCache(aclScp);
!                 return 0;
!             }
  
  	    /* check that we have a callback, too */
              if (!cm_HaveCallback(aclScp)) {
--- 48,58 ----
          if (!aclScp) 
              return 0;
          if (aclScp != scp) {
!             if (aclScp->fid.vnode < scp->fid.vnode)
!                 lock_ReleaseWrite(&scp->rw);
!             lock_ObtainRead(&aclScp->rw);
!             if (aclScp->fid.vnode < scp->fid.vnode)
!                 lock_ObtainWrite(&scp->rw);
  
  	    /* check that we have a callback, too */
              if (!cm_HaveCallback(aclScp)) {
***************
*** 167,172 ****
--- 160,167 ----
  			 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
  	if (!code) 
  	    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+     else
+         osi_Log3(afsd_logp, "GetAccessRights syncop failure scp %x user %x code %x", scp, userp, code);
      } else {
          /* not a dir, use parent dir's acl */
          cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
***************
*** 184,189 ****
--- 179,186 ----
  	if (!code)
  	    cm_SyncOpDone(aclScp, NULL, 
  			  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+     else 
+         osi_Log3(afsd_logp, "GetAccessRights parent syncop failure scp %x user %x code %x", aclScp, userp, code);
  	lock_ReleaseWrite(&aclScp->rw);
          cm_ReleaseSCache(aclScp);
          lock_ObtainWrite(&scp->rw);
Index: openafs/src/WINNT/afsd/cm_aclent.c
diff -c openafs/src/WINNT/afsd/cm_aclent.c:1.14.2.6 openafs/src/WINNT/afsd/cm_aclent.c:1.14.2.7
*** openafs/src/WINNT/afsd/cm_aclent.c:1.14.2.6	Thu Jul 31 00:34:16 2008
--- openafs/src/WINNT/afsd/cm_aclent.c	Fri Aug 22 14:10:00 2008
***************
*** 257,263 ****
      static osi_once_t once;
  
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_aclLock, "cm_aclLock");
          osi_EndOnce(&once);
      }
  
--- 257,263 ----
      static osi_once_t once;
  
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_aclLock, "cm_aclLock", LOCK_HIERARCHY_ACL_GLOBAL);
          osi_EndOnce(&once);
      }
  
Index: openafs/src/WINNT/afsd/cm_buf.c
diff -c openafs/src/WINNT/afsd/cm_buf.c:1.31.2.44 openafs/src/WINNT/afsd/cm_buf.c:1.31.2.46
*** openafs/src/WINNT/afsd/cm_buf.c:1.31.2.44	Thu Jul 31 00:41:20 2008
--- openafs/src/WINNT/afsd/cm_buf.c	Fri Aug 29 22:15:07 2008
***************
*** 213,285 ****
      }
  }
  
! /* incremental sync daemon.  Writes all dirty buffers every 5000 ms */
! void buf_IncrSyncer(long parm)
  {
      cm_buf_t **bpp, *bp, *prevbp;
-     long i;				/* counter */
      long wasDirty = 0;
      cm_req_t req;
  
!     while (buf_ShutdownFlag == 0) {
! 	if (!wasDirty) {
! 	    i = SleepEx(5000, 1);
! 	    if (i != 0) continue;
! 	}
! 
! 	wasDirty = 0;
! 
!         /* go through all of the dirty buffers */
!         lock_ObtainRead(&buf_globalLock);
!         for (bpp = &cm_data.buf_dirtyListp, prevbp = NULL; bp = *bpp; ) {
!             lock_ReleaseRead(&buf_globalLock);
! 	    /* all dirty buffers are held when they are added to the
! 	     * dirty list.  No need for an additional hold.
! 	     */
!             lock_ObtainMutex(&bp->mx);
  
! 	    if (bp->flags & CM_BUF_DIRTY) {
! 		/* start cleaning the buffer; don't touch log pages since
!  		 * the log code counts on knowing exactly who is writing
! 		 * a log page at any given instant.
! 		 */
! 		cm_InitReq(&req);
! 		req.flags |= CM_REQ_NORETRY;
! 		wasDirty |= buf_CleanAsyncLocked(bp, &req);
! 	    }
  
! 	    /* the buffer may or may not have been dirty
! 	     * and if dirty may or may not have been cleaned
! 	     * successfully.  check the dirty flag again.  
! 	     */
!             if (!(bp->flags & CM_BUF_DIRTY)) {
!                 /* remove the buffer from the dirty list */
!                 lock_ObtainWrite(&buf_globalLock);
  #ifdef DEBUG_REFCOUNT
!                 if (bp->dirtyp == NULL && bp != cm_data.buf_dirtyListEndp) {
!                     osi_Log1(afsd_logp,"buf_IncrSyncer bp 0x%p list corruption",bp);
!                     afsi_log("buf_IncrSyncer bp 0x%p list corruption", bp);
!                 }
! #endif
!                 *bpp = bp->dirtyp;
!                 bp->dirtyp = NULL;
!                 bp->flags &= ~CM_BUF_INDL;
!                 if (cm_data.buf_dirtyListp == NULL)
!                     cm_data.buf_dirtyListEndp = NULL;
!                 else if (cm_data.buf_dirtyListEndp == bp)
!                     cm_data.buf_dirtyListEndp = prevbp;
!                 buf_ReleaseLocked(bp, TRUE);
!                 lock_ConvertWToR(&buf_globalLock);
!             } else {
!                 /* advance the pointer so we don't loop forever */
!                 lock_ObtainRead(&buf_globalLock);
!                 bpp = &bp->dirtyp;
!                 prevbp = bp;
              }
!             lock_ReleaseMutex(&bp->mx);
!         }	/* for loop over a bunch of buffers */
!         lock_ReleaseRead(&buf_globalLock);
!     }		/* whole daemon's while loop */
  }
  
  long
--- 213,298 ----
      }
  }
  
! long 
! buf_Sync(int quitOnShutdown) 
  {
      cm_buf_t **bpp, *bp, *prevbp;
      long wasDirty = 0;
      cm_req_t req;
  
!     /* go through all of the dirty buffers */
!     lock_ObtainRead(&buf_globalLock);
!     for (bpp = &cm_data.buf_dirtyListp, prevbp = NULL; bp = *bpp; ) {
!         if (quitOnShutdown && buf_ShutdownFlag)
!             break;
  
!         lock_ReleaseRead(&buf_globalLock);
!         /* all dirty buffers are held when they are added to the
!         * dirty list.  No need for an additional hold.
!         */
!         lock_ObtainMutex(&bp->mx);
  
!         if (bp->flags & CM_BUF_DIRTY) {
!             /* start cleaning the buffer; don't touch log pages since
!             * the log code counts on knowing exactly who is writing
!             * a log page at any given instant.
!             */
!             cm_InitReq(&req);
!             req.flags |= CM_REQ_NORETRY;
!             wasDirty |= buf_CleanAsyncLocked(bp, &req);
!         }
! 
!         /* the buffer may or may not have been dirty
!         * and if dirty may or may not have been cleaned
!         * successfully.  check the dirty flag again.  
!         */
!         if (!(bp->flags & CM_BUF_DIRTY)) {
!             /* remove the buffer from the dirty list */
!             lock_ObtainWrite(&buf_globalLock);
  #ifdef DEBUG_REFCOUNT
!             if (bp->dirtyp == NULL && bp != cm_data.buf_dirtyListEndp) {
!                 osi_Log1(afsd_logp,"buf_IncrSyncer bp 0x%p list corruption",bp);
!                 afsi_log("buf_IncrSyncer bp 0x%p list corruption", bp);
              }
! #endif
!             *bpp = bp->dirtyp;
!             bp->dirtyp = NULL;
!             bp->flags &= ~CM_BUF_INDL;
!             if (cm_data.buf_dirtyListp == NULL)
!                 cm_data.buf_dirtyListEndp = NULL;
!             else if (cm_data.buf_dirtyListEndp == bp)
!                 cm_data.buf_dirtyListEndp = prevbp;
!             buf_ReleaseLocked(bp, TRUE);
!             lock_ConvertWToR(&buf_globalLock);
!         } else {
!             /* advance the pointer so we don't loop forever */
!             lock_ObtainRead(&buf_globalLock);
!             bpp = &bp->dirtyp;
!             prevbp = bp;
!         }
!         lock_ReleaseMutex(&bp->mx);
!     }	/* for loop over a bunch of buffers */
!     lock_ReleaseRead(&buf_globalLock);
! 
!     return wasDirty;
! }
! 
! /* incremental sync daemon.  Writes all dirty buffers every 5000 ms */
! void buf_IncrSyncer(long parm)
! {
!     long wasDirty = 0;
!     long i;
! 
!     while (buf_ShutdownFlag == 0) {
! 
!         if (!wasDirty) {
! 	    i = SleepEx(5000, 1);
! 	    if (i != 0) 
!                 continue;
! 	}
! 
!         wasDirty = buf_Sync(1);
!     } /* whole daemon's while loop */
  }
  
  long
***************
*** 359,366 ****
  }
  
  void buf_Shutdown(void)  
! {                        
      buf_ShutdownFlag = 1;
  }                        
  
  /* initialize the buffer package; called with no locks
--- 372,383 ----
  }
  
  void buf_Shutdown(void)  
! {  
!     /* disable the buf_IncrSyncer() threads */
      buf_ShutdownFlag = 1;
+ 
+     /* then force all dirty buffers to the file servers */
+     buf_Sync(0);
  }                        
  
  /* initialize the buffer package; called with no locks
***************
*** 389,395 ****
  
      if (osi_Once(&once)) {
          /* initialize global locks */
!         lock_InitializeRWLock(&buf_globalLock, "Global buffer lock");
  
          if ( newFile ) {
              /* remember this for those who want to reset it */
--- 406,412 ----
  
      if (osi_Once(&once)) {
          /* initialize global locks */
!         lock_InitializeRWLock(&buf_globalLock, "Global buffer lock", LOCK_HIERARCHY_BUF_GLOBAL);
  
          if ( newFile ) {
              /* remember this for those who want to reset it */
***************
*** 424,430 ****
                  
                  osi_QAdd((osi_queue_t **)&cm_data.buf_freeListp, &bp->q);
                  bp->flags |= CM_BUF_INLRU;
!                 lock_InitializeMutex(&bp->mx, "Buffer mutex");
                  
                  /* grab appropriate number of bytes from aligned zone */
                  bp->datap = data;
--- 441,447 ----
                  
                  osi_QAdd((osi_queue_t **)&cm_data.buf_freeListp, &bp->q);
                  bp->flags |= CM_BUF_INLRU;
!                 lock_InitializeMutex(&bp->mx, "Buffer mutex", LOCK_HIERARCHY_BUFFER);
                  
                  /* grab appropriate number of bytes from aligned zone */
                  bp->datap = data;
***************
*** 448,454 ****
              data = cm_data.bufDataBaseAddress;
              
              for (i=0; i<cm_data.buf_nbuffers; i++) {
!                 lock_InitializeMutex(&bp->mx, "Buffer mutex");
                  bp->userp = NULL;
                  bp->waitCount = 0;
                  bp->waitRequests = 0;
--- 465,471 ----
              data = cm_data.bufDataBaseAddress;
              
              for (i=0; i<cm_data.buf_nbuffers; i++) {
!                 lock_InitializeMutex(&bp->mx, "Buffer mutex", LOCK_HIERARCHY_BUFFER);
                  bp->userp = NULL;
                  bp->waitCount = 0;
                  bp->waitRequests = 0;
***************
*** 516,522 ****
      for (i=0; i<nbuffers; i++) {
          memset(bp, 0, sizeof(*bp));
          
!         lock_InitializeMutex(&bp->mx, "cm_buf_t");
  
          /* grab appropriate number of bytes from aligned zone */
          bp->datap = data;
--- 533,539 ----
      for (i=0; i<nbuffers; i++) {
          memset(bp, 0, sizeof(*bp));
          
!         lock_InitializeMutex(&bp->mx, "cm_buf_t", LOCK_HIERARCHY_BUFFER);
  
          /* grab appropriate number of bytes from aligned zone */
          bp->datap = data;
***************
*** 998,1021 ****
              osi_QRemove((osi_queue_t **) &cm_data.buf_freeListp, &bp->q);
              bp->flags &= ~CM_BUF_INLRU;
  
              /* grab the mutex so that people don't use it
               * before the caller fills it with data.  Again, no one	
               * should have been able to get to this dude to lock it.
               */
  	    if (!lock_TryMutex(&bp->mx)) {
  	    	osi_Log2(afsd_logp, "buf_GetNewLocked bp 0x%p cannot be mutex locked.  refCount %d should be 0",
! 			 bp, bp->refCount);
  		osi_panic("buf_GetNewLocked: TryMutex failed",__FILE__,__LINE__);
  	    }
  
- 	    /* prepare to return it.  Give it a refcount */
-             bp->refCount = 1;
- #ifdef DEBUG_REFCOUNT
-             osi_Log2(afsd_logp,"buf_GetNewLocked bp 0x%p ref %d", bp, 1);
-             afsi_log("%s:%d buf_GetNewLocked bp 0x%p, ref %d", __FILE__, __LINE__, bp, 1);
- #endif
              lock_ReleaseWrite(&buf_globalLock);
              lock_ReleaseRead(&scp->bufCreateLock);
              *bufpp = bp;
  
  #ifdef TESTING
--- 1015,1039 ----
              osi_QRemove((osi_queue_t **) &cm_data.buf_freeListp, &bp->q);
              bp->flags &= ~CM_BUF_INLRU;
  
+             /* prepare to return it.  Give it a refcount */
+             bp->refCount = 1;
+ #ifdef DEBUG_REFCOUNT
+             osi_Log2(afsd_logp,"buf_GetNewLocked bp 0x%p ref %d", bp, 1);
+             afsi_log("%s:%d buf_GetNewLocked bp 0x%p, ref %d", __FILE__, __LINE__, bp, 1);
+ #endif
              /* grab the mutex so that people don't use it
               * before the caller fills it with data.  Again, no one	
               * should have been able to get to this dude to lock it.
               */
  	    if (!lock_TryMutex(&bp->mx)) {
  	    	osi_Log2(afsd_logp, "buf_GetNewLocked bp 0x%p cannot be mutex locked.  refCount %d should be 0",
!                          bp, bp->refCount);
  		osi_panic("buf_GetNewLocked: TryMutex failed",__FILE__,__LINE__);
  	    }
  
              lock_ReleaseWrite(&buf_globalLock);
              lock_ReleaseRead(&scp->bufCreateLock);
+ 
              *bufpp = bp;
  
  #ifdef TESTING
Index: openafs/src/WINNT/afsd/cm_callback.c
diff -c openafs/src/WINNT/afsd/cm_callback.c:1.41.4.47 openafs/src/WINNT/afsd/cm_callback.c:1.41.4.51
*** openafs/src/WINNT/afsd/cm_callback.c:1.41.4.47	Fri Aug  1 15:13:51 2008
--- openafs/src/WINNT/afsd/cm_callback.c	Sat Sep 13 00:20:48 2008
***************
*** 599,605 ****
  extern osi_rwlock_t smb_rctLock;
  
  extern osi_mutex_t cm_Freelance_Lock;
- extern osi_mutex_t cm_bufGetMutex;
  extern osi_mutex_t cm_Afsdsbmt_Lock;
  extern osi_mutex_t tokenEventLock;
  extern osi_mutex_t  smb_ListenerLock;
--- 599,604 ----
***************
*** 629,635 ****
      {"smb_globalLock",   (char*)&smb_globalLock,        LOCKTYPE_RW},
      {"smb_rctLock",      (char*)&smb_rctLock,           LOCKTYPE_RW},
      {"cm_Freelance_Lock",(char*)&cm_Freelance_Lock,     LOCKTYPE_MUTEX},
-     {"cm_bufGetMutex",   (char*)&cm_bufGetMutex,        LOCKTYPE_MUTEX},
      {"cm_Afsdsbmt_Lock", (char*)&cm_Afsdsbmt_Lock,      LOCKTYPE_MUTEX},
      {"tokenEventLock",   (char*)&tokenEventLock,        LOCKTYPE_MUTEX},
      {"smb_ListenerLock", (char*)&smb_ListenerLock,      LOCKTYPE_MUTEX},
--- 628,633 ----
***************
*** 1493,1499 ****
  /* called by afsd without any locks to initialize this module */
  void cm_InitCallback(void)
  {
!     lock_InitializeRWLock(&cm_callbackLock, "cm_callbackLock");
      cm_activeCallbackGrantingCalls = 0;
  }
  
--- 1491,1497 ----
  /* called by afsd without any locks to initialize this module */
  void cm_InitCallback(void)
  {
!     lock_InitializeRWLock(&cm_callbackLock, "cm_callbackLock", LOCK_HIERARCHY_CALLBACK_GLOBAL);
      cm_activeCallbackGrantingCalls = 0;
  }
  
***************
*** 1869,1874 ****
--- 1867,1874 ----
          return 1;
  
      for (found = 0,tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
+         if (tsrp->status == srv_deleted)
+             continue;
          if (tsrp->server == scp->cbServerp)
              found = 1;
          if (tsrp->server->downTime > *downTime)
***************
*** 1951,1963 ****
              cm_volume_t * volp;
              int i;
  
              lock_ObtainMutex(&tsp->mx);
              if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                  tsp->flags |= CM_SERVERFLAG_DOWN;
                  tsp->downTime = time(NULL);
              }
-             cm_ForceNewConnections(tsp);
- 
              /* Now update the volume status */
              for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
                  for (i=0; i<NUM_SERVER_VOLS; i++) {
--- 1951,1963 ----
              cm_volume_t * volp;
              int i;
  
+             cm_ForceNewConnections(tsp);
+ 
              lock_ObtainMutex(&tsp->mx);
              if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                  tsp->flags |= CM_SERVERFLAG_DOWN;
                  tsp->downTime = time(NULL);
              }
              /* Now update the volume status */
              for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
                  for (i=0; i<NUM_SERVER_VOLS; i++) {
***************
*** 1965,1977 ****
                          cm_req_t req;
  
                          cm_InitReq(&req);
! 
                          code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
                                                   &req, CM_GETVOL_FLAG_NO_LRU_UPDATE | CM_GETVOL_FLAG_NO_RESET, &volp);
                          if (code == 0) {    
                              cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
                              cm_PutVolume(volp);
!                         }
                      }
                  }
              }
--- 1965,1978 ----
                          cm_req_t req;
  
                          cm_InitReq(&req);
!                         lock_ReleaseMutex(&tsp->mx);
                          code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
                                                   &req, CM_GETVOL_FLAG_NO_LRU_UPDATE | CM_GETVOL_FLAG_NO_RESET, &volp);
+                         lock_ObtainMutex(&tsp->mx);
                          if (code == 0) {    
                              cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
                              cm_PutVolume(volp);
!                         }       
                      }
                  }
              }
Index: openafs/src/WINNT/afsd/cm_cell.c
diff -c openafs/src/WINNT/afsd/cm_cell.c:1.23.2.18 openafs/src/WINNT/afsd/cm_cell.c:1.23.2.25
*** openafs/src/WINNT/afsd/cm_cell.c:1.23.2.18	Thu Aug 14 13:25:04 2008
--- openafs/src/WINNT/afsd/cm_cell.c	Thu Sep 11 13:05:32 2008
***************
*** 87,93 ****
          || (cm_dnsEnabled && (cp->flags & CM_CELLFLAG_DNS) &&
           ((cp->flags & CM_CELLFLAG_VLSERVER_INVALID)))
  #endif
!             ) {
          /* must empty cp->vlServersp */
          if (cp->vlServersp) {
              cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
--- 87,96 ----
          || (cm_dnsEnabled && (cp->flags & CM_CELLFLAG_DNS) &&
           ((cp->flags & CM_CELLFLAG_VLSERVER_INVALID)))
  #endif
!             ) 
!     {
!         lock_ReleaseMutex(&cp->mx);
! 
          /* must empty cp->vlServersp */
          if (cp->vlServersp) {
              cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
***************
*** 97,112 ****
          rock.cellp = cp;
          rock.flags = flags;
          code = cm_SearchCellFile(cp->name, NULL, cm_AddCellProc, &rock);
  #ifdef AFS_AFSDB_ENV
!         if (code) {
              if (cm_dnsEnabled) {
                  int ttl;
  
                  code = cm_SearchCellByDNS(cp->name, NULL, &ttl, cm_AddCellProc, &rock);
                  if (code == 0) {   /* got cell from DNS */
                      cp->flags |= CM_CELLFLAG_DNS;
                      cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
  		    cp->timeout = time(0) + ttl;
  #ifdef DEBUG
                      fprintf(stderr, "cell %s: ttl=%d\n", cp->name, ttl);
  #endif
--- 100,122 ----
          rock.cellp = cp;
          rock.flags = flags;
          code = cm_SearchCellFile(cp->name, NULL, cm_AddCellProc, &rock);
+         if (code == 0) {
+             lock_ObtainMutex(&cp->mx);
+ 	    cp->timeout = time(0) + 7200;
+             lock_ReleaseMutex(&cp->mx);
+         }
  #ifdef AFS_AFSDB_ENV
!         else {
              if (cm_dnsEnabled) {
                  int ttl;
  
                  code = cm_SearchCellByDNS(cp->name, NULL, &ttl, cm_AddCellProc, &rock);
                  if (code == 0) {   /* got cell from DNS */
+                     lock_ObtainMutex(&cp->mx);
                      cp->flags |= CM_CELLFLAG_DNS;
                      cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
  		    cp->timeout = time(0) + ttl;
+                     lock_ReleaseMutex(&cp->mx);
  #ifdef DEBUG
                      fprintf(stderr, "cell %s: ttl=%d\n", cp->name, ttl);
  #endif
***************
*** 114,129 ****
                      /* if we fail to find it this time, we'll just do nothing and leave the
                       * current entry alone 
  		     */
                      cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
                  }
  	    }
! 	} else 
  #endif /* AFS_AFSDB_ENV */
! 	{
! 	    cp->timeout = time(0) + 7200;
! 	}	
      }
-     lock_ReleaseMutex(&cp->mx);
      return code ? NULL : cp;
  }
  
--- 124,139 ----
                      /* if we fail to find it this time, we'll just do nothing and leave the
                       * current entry alone 
  		     */
+                     lock_ObtainMutex(&cp->mx);
                      cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
+                     lock_ReleaseMutex(&cp->mx);
                  }
  	    }
! 	}
  #endif /* AFS_AFSDB_ENV */
!     } else {
!         lock_ReleaseMutex(&cp->mx);
      }
      return code ? NULL : cp;
  }
  
***************
*** 133,144 ****
--- 143,165 ----
      return cm_GetCell_Gen(namep, NULL, flags);
  }
  
+ void cm_FreeCell(cm_cell_t *cellp)
+ {
+     if (cellp->vlServersp)
+         cm_FreeServerList(&cellp->vlServersp, CM_FREESERVERLIST_DELETE);
+     cellp->name[0] = '\0';    
+ 
+     cellp->freeNextp = cm_data.freeCellsp;
+     cm_data.freeCellsp = cellp;
+ }
+ 
  cm_cell_t *cm_GetCell_Gen(char *namep, char *newnamep, afs_uint32 flags)
  {
      cm_cell_t *cp, *cp2;
      long code;
      char fullname[CELL_MAXNAMELEN]="";
      int  hasWriteLock = 0;
+     int  hasMutex = 0;
      afs_uint32 hash;
      cm_cell_rock_t rock;
  
***************
*** 166,177 ****
          }   
      }
  
-     lock_ReleaseRead(&cm_cellLock);
- 
      if (cp) {
          cm_UpdateCell(cp, flags);
      } else if (flags & CM_FLAG_CREATE) {
!         lock_ObtainWrite(&cm_cellLock);
          hasWriteLock = 1;
  
          /* when we dropped the lock the cell could have been added
--- 187,197 ----
          }   
      }
  
      if (cp) {
+         lock_ReleaseRead(&cm_cellLock);
          cm_UpdateCell(cp, flags);
      } else if (flags & CM_FLAG_CREATE) {
!         lock_ConvertRToW(&cm_cellLock);
          hasWriteLock = 1;
  
          /* when we dropped the lock the cell could have been added
***************
*** 196,214 ****
              }
          }   
  
!         if (cp)
              goto done;
  
!         if ( cm_data.currentCells >= cm_data.maxCells )
!             osi_panic("Exceeded Max Cells", __FILE__, __LINE__);
  
-         /* don't increment currentCells until we know that we 
-          * are going to keep this entry 
-          */
-         cp = &cm_data.cellBaseAddress[cm_data.currentCells];
-         memset(cp, 0, sizeof(cm_cell_t));
-         cp->magic = CM_CELL_MAGIC;
-         
          rock.cellp = cp;
          rock.flags = flags;
          code = cm_SearchCellFile(namep, fullname, cm_AddCellProc, &rock);
--- 216,257 ----
              }
          }   
  
!         if (cp) {
!             lock_ObtainMutex(&cp->mx);
!             cm_AddCellToNameHashTable(cp);
!             cm_AddCellToIDHashTable(cp);           
!             lock_ReleaseMutex(&cp->mx);
              goto done;
+         }
  
!         if ( cm_data.freeCellsp != NULL ) {
!             cp = cm_data.freeCellsp;
!             cm_data.freeCellsp = cp->freeNextp;
! 
!             /* 
!              * The magic, cellID, and mx fields are already set.
!              */
!         } else {
!             if ( cm_data.currentCells >= cm_data.maxCells )
!                 osi_panic("Exceeded Max Cells", __FILE__, __LINE__);
! 
!             /* don't increment currentCells until we know that we 
!              * are going to keep this entry 
!              */
!             cp = &cm_data.cellBaseAddress[cm_data.currentCells];
!             memset(cp, 0, sizeof(cm_cell_t));
!             cp->magic = CM_CELL_MAGIC;
! 
!             /* the cellID cannot be 0 */
!             cp->cellID = ++cm_data.currentCells;
! 
!             /* otherwise we found the cell, and so we're nearly done */
!             lock_InitializeMutex(&cp->mx, "cm_cell_t mutex", LOCK_HIERARCHY_CELL);
!         }
! 
!         lock_ReleaseWrite(&cm_cellLock);
!         hasWriteLock = 0;
  
          rock.cellp = cp;
          rock.flags = flags;
          code = cm_SearchCellFile(namep, fullname, cm_AddCellProc, &rock);
***************
*** 224,244 ****
                  if ( code ) {
                      osi_Log3(afsd_logp,"in cm_GetCell_gen cm_SearchCellByDNS(%s) returns code= %d fullname= %s", 
                               osi_LogSaveString(afsd_logp,namep), code, osi_LogSaveString(afsd_logp,fullname));
                      cp = NULL;
                      goto done;
                  } else {   /* got cell from DNS */
                      cp->flags |= CM_CELLFLAG_DNS;
                      cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
                      cp->timeout = time(0) + ttl;
                  }
!             } else {
  #endif
                  cp = NULL;
                  goto done;
- #ifdef AFS_AFSDB_ENV
  	    }
- #endif
          } else {
  	    cp->timeout = time(0) + 7200;	/* two hour timeout */
  	}
  
--- 267,293 ----
                  if ( code ) {
                      osi_Log3(afsd_logp,"in cm_GetCell_gen cm_SearchCellByDNS(%s) returns code= %d fullname= %s", 
                               osi_LogSaveString(afsd_logp,namep), code, osi_LogSaveString(afsd_logp,fullname));
+                     cm_FreeCell(cp);
                      cp = NULL;
                      goto done;
                  } else {   /* got cell from DNS */
+                     lock_ObtainMutex(&cp->mx);
+                     hasMutex = 1;
                      cp->flags |= CM_CELLFLAG_DNS;
                      cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
                      cp->timeout = time(0) + ttl;
                  }
!             } 
!             else 
  #endif
+             {
+                 cm_FreeCell(cp);
                  cp = NULL;
                  goto done;
  	    }
          } else {
+             lock_ObtainMutex(&cp->mx);
+             hasMutex = 1;
  	    cp->timeout = time(0) + 7200;	/* two hour timeout */
  	}
  
***************
*** 255,280 ****
          }   
  
          if (cp2) {
!             cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
              cp = cp2;
              goto done;
          }
  
- 
          /* randomise among those vlservers having the same rank*/ 
          cm_RandomizeServer(&cp->vlServersp);
  
!         /* otherwise we found the cell, and so we're nearly done */
!         lock_InitializeMutex(&cp->mx, "cm_cell_t mutex");
! 
          /* copy in name */
          strncpy(cp->name, fullname, CELL_MAXNAMELEN);
          cp->name[CELL_MAXNAMELEN-1] = '\0';
  
!         /* the cellID cannot be 0 */
!         cp->cellID = ++cm_data.currentCells;
  
! 		/* append cell to global list */
          if (cm_data.allCellsp == NULL) {
              cm_data.allCellsp = cp;
          } else {
--- 304,333 ----
          }   
  
          if (cp2) {
!             if (hasMutex) {
!                 lock_ReleaseMutex(&cp->mx);
!                 hasMutex = 0;
!             }
!             cm_FreeCell(cp);
              cp = cp2;
              goto done;
          }
  
          /* randomise among those vlservers having the same rank*/ 
          cm_RandomizeServer(&cp->vlServersp);
  
!         if (!hasMutex)
!             lock_ObtainMutex(&cp->mx);
          /* copy in name */
          strncpy(cp->name, fullname, CELL_MAXNAMELEN);
          cp->name[CELL_MAXNAMELEN-1] = '\0';
  
!         cm_AddCellToNameHashTable(cp);
!         cm_AddCellToIDHashTable(cp);           
!         lock_ReleaseMutex(&cp->mx);
!         hasMutex = 0;
  
!         /* append cell to global list */
          if (cm_data.allCellsp == NULL) {
              cm_data.allCellsp = cp;
          } else {
***************
*** 284,301 ****
          }
          cp->allNextp = NULL;
  
!         cm_AddCellToNameHashTable(cp);
!         cm_AddCellToIDHashTable(cp);           
      }
- 
    done:
      if (hasWriteLock)
          lock_ReleaseWrite(&cm_cellLock);
      
      /* fullname is not valid if cp == NULL */
!     if (cp && newnamep) {
!         strncpy(newnamep, fullname, CELL_MAXNAMELEN);
!         newnamep[CELL_MAXNAMELEN-1]='\0';
      }
      return cp;
  }
--- 337,359 ----
          }
          cp->allNextp = NULL;
  
!     } else {
!         lock_ReleaseRead(&cm_cellLock);
      }
    done:
+     if (hasMutex && cp)
+         lock_ReleaseMutex(&cp->mx);
      if (hasWriteLock)
          lock_ReleaseWrite(&cm_cellLock);
      
      /* fullname is not valid if cp == NULL */
!     if (newnamep) {
!         if (cp) {
!             strncpy(newnamep, fullname, CELL_MAXNAMELEN);
!             newnamep[CELL_MAXNAMELEN-1]='\0';
!         } else {
!             newnamep[0] = '\0';
!         }
      }
      return cp;
  }
***************
*** 341,350 ****
          }
      }
  
      if ( count != cm_data.currentCells ) {
          afsi_log("cm_ValidateCell failure: count != cm_data.currentCells");
          fprintf(stderr, "cm_ValidateCell failure: count != cm_data.currentCells\n");
!         return -3;
      }
      
      return 0;
--- 399,417 ----
          }
      }
  
+     for (cellp = cm_data.freeCellsp; cellp; cellp=cellp->freeNextp, count++) {
+         if ( count != 0 && cellp == cm_data.freeCellsp ||
+              count > cm_data.maxCells ) {
+             afsi_log("cm_ValidateCell failure: cm_data.freeCellsp infinite loop");
+             fprintf(stderr, "cm_ValidateCell failure: cm_data.freeCellsp infinite loop\n");
+             return -3;
+         }
+     }
+ 
      if ( count != cm_data.currentCells ) {
          afsi_log("cm_ValidateCell failure: count != cm_data.currentCells");
          fprintf(stderr, "cm_ValidateCell failure: count != cm_data.currentCells\n");
!         return -4;
      }
      
      return 0;
***************
*** 370,376 ****
      if (osi_Once(&once)) {
          cm_cell_t * cellp;
  
!         lock_InitializeRWLock(&cm_cellLock, "cell global lock");
  
          if ( newFile ) {
              cm_data.allCellsp = NULL;
--- 437,443 ----
      if (osi_Once(&once)) {
          cm_cell_t * cellp;
  
!         lock_InitializeRWLock(&cm_cellLock, "cell global lock", LOCK_HIERARCHY_CELL_GLOBAL);
  
          if ( newFile ) {
              cm_data.allCellsp = NULL;
***************
*** 388,394 ****
              memset(cellp, 0, sizeof(cm_cell_t));
              cellp->magic = CM_CELL_MAGIC;
  
!             lock_InitializeMutex(&cellp->mx, "cm_cell_t mutex");
  
              /* copy in name */
              strncpy(cellp->name, "Freelance.Local.Cell", CELL_MAXNAMELEN); /*safe*/
--- 455,461 ----
              memset(cellp, 0, sizeof(cm_cell_t));
              cellp->magic = CM_CELL_MAGIC;
  
!             lock_InitializeMutex(&cellp->mx, "cm_cell_t mutex", LOCK_HIERARCHY_CELL);
  
              /* copy in name */
              strncpy(cellp->name, "Freelance.Local.Cell", CELL_MAXNAMELEN); /*safe*/
***************
*** 402,413 ****
              cellp->vlServersp = NULL;
              cellp->flags = CM_CELLFLAG_FREELANCE;
  
! 	    cm_AddCellToNameHashTable(cellp);
! 	    cm_AddCellToIDHashTable(cellp);           
  #endif  
          } else {
              for (cellp = cm_data.allCellsp; cellp; cellp=cellp->allNextp) {
!                 lock_InitializeMutex(&cellp->mx, "cm_cell_t mutex");
                  cellp->vlServersp = NULL;
                  cellp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
              }
--- 469,482 ----
              cellp->vlServersp = NULL;
              cellp->flags = CM_CELLFLAG_FREELANCE;
  
!             lock_ObtainMutex(&cellp->mx);
!             cm_AddCellToNameHashTable(cellp);
!             cm_AddCellToIDHashTable(cellp);           
!             lock_ReleaseMutex(&cellp->mx);
  #endif  
          } else {
              for (cellp = cm_data.allCellsp; cellp; cellp=cellp->allNextp) {
!                 lock_InitializeMutex(&cellp->mx, "cm_cell_t mutex", LOCK_HIERARCHY_CELL);
                  cellp->vlServersp = NULL;
                  cellp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
              }
Index: openafs/src/WINNT/afsd/cm_cell.h
diff -c openafs/src/WINNT/afsd/cm_cell.h:1.7.6.8 openafs/src/WINNT/afsd/cm_cell.h:1.7.6.10
*** openafs/src/WINNT/afsd/cm_cell.h:1.7.6.8	Thu Feb 14 22:31:36 2008
--- openafs/src/WINNT/afsd/cm_cell.h	Tue Sep  2 16:18:33 2008
***************
*** 21,35 ****
      struct cm_cell *allNextp;	        /* locked by cm_cellLock */
      struct cm_cell *nameNextp;	        /* locked by cm_cellLock */
      struct cm_cell *idNextp;	        /* locked by cm_cellLock */
      char name[CELL_MAXNAMELEN];         /* cell name; never changes */
      cm_serverRef_t *vlServersp;         /* locked by cm_serverLock */
      osi_mutex_t mx;			/* mutex locking fields (flags) */
      long flags;			        /* locked by mx */
!     time_t timeout;                     /* if dns, time at which the server addrs expire */
  } cm_cell_t;
  
  /* These are bit flag values */
! #define CM_CELLFLAG_SUID	       1	/* setuid flag; not yet used */
  #define CM_CELLFLAG_DNS                2  /* cell servers are from DNS */
  #define CM_CELLFLAG_VLSERVER_INVALID   4  /* cell servers are invalid */
  #define CM_CELLFLAG_FREELANCE          8  /* local freelance fake cell */
--- 21,36 ----
      struct cm_cell *allNextp;	        /* locked by cm_cellLock */
      struct cm_cell *nameNextp;	        /* locked by cm_cellLock */
      struct cm_cell *idNextp;	        /* locked by cm_cellLock */
+     struct cm_cell *freeNextp;
      char name[CELL_MAXNAMELEN];         /* cell name; never changes */
      cm_serverRef_t *vlServersp;         /* locked by cm_serverLock */
      osi_mutex_t mx;			/* mutex locking fields (flags) */
      long flags;			        /* locked by mx */
!     time_t timeout;                     /* if dns, time at which the server addrs expire (mx) */
  } cm_cell_t;
  
  /* These are bit flag values */
! #define CM_CELLFLAG_SUID	       1  /* setuid flag; not yet used */
  #define CM_CELLFLAG_DNS                2  /* cell servers are from DNS */
  #define CM_CELLFLAG_VLSERVER_INVALID   4  /* cell servers are invalid */
  #define CM_CELLFLAG_FREELANCE          8  /* local freelance fake cell */
Index: openafs/src/WINNT/afsd/cm_conn.c
diff -c openafs/src/WINNT/afsd/cm_conn.c:1.49.2.47 openafs/src/WINNT/afsd/cm_conn.c:1.49.2.54
*** openafs/src/WINNT/afsd/cm_conn.c:1.49.2.47	Thu Aug 14 16:24:03 2008
--- openafs/src/WINNT/afsd/cm_conn.c	Wed Sep 24 18:42:53 2008
***************
*** 49,55 ****
      HKEY parmKey;
          
      if (osi_Once(&once)) {
! 	lock_InitializeRWLock(&cm_connLock, "connection global lock");
  
          /* keisa - read timeout value for lanmanworkstation  service.
           * jaltman - as per 
--- 49,56 ----
      HKEY parmKey;
          
      if (osi_Once(&once)) {
! 	lock_InitializeRWLock(&cm_connLock, "connection global lock",
!                                LOCK_HIERARCHY_CONN_GLOBAL);
  
          /* keisa - read timeout value for lanmanworkstation  service.
           * jaltman - as per 
***************
*** 140,151 ****
      if (code) 
          return code;
      
!     *serversppp = cm_GetVolServers(volp, fidp->volume);
  
      lock_ObtainRead(&cm_volumeLock);
      cm_PutVolume(volp);
      lock_ReleaseRead(&cm_volumeLock);
!     return 0;
  }
  
  /*
--- 141,152 ----
      if (code) 
          return code;
      
!     *serversppp = cm_GetVolServers(volp, fidp->volume, userp, reqp);
  
      lock_ObtainRead(&cm_volumeLock);
      cm_PutVolume(volp);
      lock_ReleaseRead(&cm_volumeLock);
!     return (*serversppp ? 0 : CM_ERROR_NOSUCHVOLUME);
  }
  
  /*
***************
*** 231,236 ****
--- 232,239 ----
          if (cellp == NULL && serversp) {
              struct cm_serverRef * refp;
              for ( refp=serversp ; cellp == NULL && refp != NULL; refp=refp->next) {
+                 if (refp->status == srv_deleted)
+                     continue;
                  if ( refp->server )
                      cellp = refp->server->cellp;
              }
***************
*** 265,278 ****
       */
      else if (errorCode == CM_ERROR_NOSUCHVOLUME) {
  	osi_Log0(afsd_logp, "cm_Analyze passed CM_ERROR_NOSUCHVOLUME.");
!         if (timeLeft > 7) {
!             thrd_Sleep(5000);
!             
!             retry = 1;
! 
!             if (fidp != NULL)   /* Not a VLDB call */
!                 cm_ForceUpdateVolume(fidp, userp, reqp);
!         }
      }
  
      else if (errorCode == CM_ERROR_ALLDOWN) {
--- 268,277 ----
       */
      else if (errorCode == CM_ERROR_NOSUCHVOLUME) {
  	osi_Log0(afsd_logp, "cm_Analyze passed CM_ERROR_NOSUCHVOLUME.");
!         /* 
!          * The VNOVOL or VL_NOENT error has already been translated
!          * to CM_ERROR_NOSUCHVOLUME.  There is nothing for us to do.
!          */
      }
  
      else if (errorCode == CM_ERROR_ALLDOWN) {
***************
*** 338,343 ****
--- 337,344 ----
                          }
                          lock_ObtainWrite(&cm_serverLock);
                          for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+                             if (tsrp->status == srv_deleted)
+                                 continue;
                              if (tsrp->status == srv_busy) {
                                  tsrp->status = srv_not_busy;
                              }       
***************
*** 345,351 ****
                          lock_ReleaseWrite(&cm_serverLock);
                          if (free_svr_list) {
                              cm_FreeServerList(&serversp, 0);
!                             *serverspp = serversp;
                          }
  
                          cm_UpdateVolumeStatus(volp, fidp->volume);
--- 346,353 ----
                          lock_ReleaseWrite(&cm_serverLock);
                          if (free_svr_list) {
                              cm_FreeServerList(&serversp, 0);
!                             *serverspp = serversp = NULL;
!                             free_svr_list = 0;
                          }
  
                          cm_UpdateVolumeStatus(volp, fidp->volume);
***************
*** 367,372 ****
--- 369,376 ----
                  if (serversp) {
                      lock_ObtainWrite(&cm_serverLock);
                      for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+                         if (tsrp->status == srv_deleted)
+                             continue;
                          if (tsrp->status == srv_busy) {
                              tsrp->status = srv_not_busy;
                          }
***************
*** 389,402 ****
--- 393,410 ----
          }
          lock_ObtainWrite(&cm_serverLock);
          for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+             if (tsrp->status == srv_deleted)
+                 continue;
              if (tsrp->server == serverp && tsrp->status == srv_not_busy) {
                  tsrp->status = srv_busy;
                  if (fidp) { /* File Server query */
+                     lock_ReleaseWrite(&cm_serverLock);
                      code = cm_FindVolumeByID(cellp, fidp->volume, userp, reqp, 
                                               CM_GETVOL_FLAG_NO_LRU_UPDATE, 
                                               &volp);
                      if (code == 0)
                          statep = cm_VolumeStateByID(volp, fidp->volume);
+                     lock_ObtainWrite(&cm_serverLock);
                  }
                  break;
              }
***************
*** 413,419 ****
  
          if (free_svr_list) {
              cm_FreeServerList(&serversp, 0);
!             *serverspp = serversp;
          }
          retry = 1;
      }
--- 421,428 ----
  
          if (free_svr_list) {
              cm_FreeServerList(&serversp, 0);
!             *serverspp = serversp = NULL;
!             free_svr_list = 0;
          }
          retry = 1;
      }
***************
*** 428,434 ****
          switch ( errorCode ) {
          case VNOVOL:
  	    msgID = MSG_SERVER_REPORTS_VNOVOL;
!             format = "Server %s reported volume %d as not attached.";
              break;
          case VMOVED:
  	    msgID = MSG_SERVER_REPORTS_VMOVED;
--- 437,443 ----
          switch ( errorCode ) {
          case VNOVOL:
  	    msgID = MSG_SERVER_REPORTS_VNOVOL;
!             format = "Server %s reported volume %d as not attached (does not exist).";
              break;
          case VMOVED:
  	    msgID = MSG_SERVER_REPORTS_VMOVED;
***************
*** 468,514 ****
          if (!serversp && fidp) {
              code = cm_GetServerList(fidp, userp, reqp, &serverspp);
              if (code == 0) {
!                 serversp = *serverspp;
                  free_svr_list = 1;
              }
          }
  
          lock_ObtainWrite(&cm_serverLock);
          for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
              if (tsrp->server == serverp) {
                  /* REDIRECT */
!                 if (errorCode == VMOVED) {
                      tsrp->status = srv_deleted;
                  } else {
                      tsrp->status = srv_offline;
                  }
- 
-                 if (fidp) { /* File Server query */
-                     code = cm_FindVolumeByID(cellp, fidp->volume, userp, reqp, 
-                                              CM_GETVOL_FLAG_NO_LRU_UPDATE, 
-                                              &volp);
-                     if (code == 0)
-                         cm_VolumeStateByID(volp, fidp->volume);
-                 }   
              }
          }   
          lock_ReleaseWrite(&cm_serverLock);
  
!         if (fidp && errorCode == VMOVED)
!             cm_ForceUpdateVolume(fidp, userp, reqp);
! 
!         if (statep) {
!             cm_UpdateVolumeStatus(volp, statep->ID);
!             lock_ObtainRead(&cm_volumeLock);
!             cm_PutVolume(volp);
!             lock_ReleaseRead(&cm_volumeLock);
!             volp = NULL;
!         }
! 
          if (free_svr_list) {
              cm_FreeServerList(&serversp, 0);
!             *serverspp = serversp;
          }
          if ( timeLeft > 2 )
              retry = 1;
      } else if ( errorCode == VNOVNODE ) {
--- 477,540 ----
          if (!serversp && fidp) {
              code = cm_GetServerList(fidp, userp, reqp, &serverspp);
              if (code == 0) {
!                 serversp = *serverspp = NULL;
                  free_svr_list = 1;
              }
          }
  
          lock_ObtainWrite(&cm_serverLock);
          for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+             if (tsrp->status == srv_deleted)
+                 continue;
              if (tsrp->server == serverp) {
                  /* REDIRECT */
!                 if (errorCode == VMOVED || errorCode == VNOVOL) {
                      tsrp->status = srv_deleted;
+                     if (fidp)
+                         cm_RemoveVolumeFromServer(serverp, fidp->volume);
                  } else {
                      tsrp->status = srv_offline;
                  }
              }
          }   
          lock_ReleaseWrite(&cm_serverLock);
  
!         /* Free the server list before cm_ForceUpdateVolume is called */
          if (free_svr_list) {
              cm_FreeServerList(&serversp, 0);
!             *serverspp = serversp = NULL;
!             free_svr_list = 0;
!         }
! 
!         if (fidp) { /* File Server query */
!             code = cm_FindVolumeByID(cellp, fidp->volume, userp, reqp, 
!                                       CM_GETVOL_FLAG_NO_LRU_UPDATE, 
!                                       &volp);
!             if (code == 0)
!                 statep = cm_VolumeStateByID(volp, fidp->volume);
! 
!             if (errorCode == VMOVED || errorCode == VNOVOL) {
!                 code = cm_ForceUpdateVolume(fidp, userp, reqp);
!                 if (code) 
!                     timeLeft = 0;   /* prevent a retry on failure */
!                 osi_Log3(afsd_logp, "cm_Analyze called cm_ForceUpdateVolume cell %u vol %u code 0x%x",
!                         fidp->cell, fidp->volume, code);
!             }
! 
!             if (statep) {
!                 cm_UpdateVolumeStatus(volp, statep->ID);
!                 osi_Log3(afsd_logp, "cm_Analyze NewVolState cell %u vol %u state %u", 
!                          fidp->cell, fidp->volume, statep->state);
!             }
! 
!             if (volp) {
!                 lock_ObtainRead(&cm_volumeLock);
!                 cm_PutVolume(volp);
!                 lock_ReleaseRead(&cm_volumeLock);
!                 volp = NULL;
!             }
          }
+ 
          if ( timeLeft > 2 )
              retry = 1;
      } else if ( errorCode == VNOVNODE ) {
***************
*** 609,614 ****
--- 635,653 ----
              reqp->tokenError = errorCode;
              retry = 1;
          }
+     } else if (errorCode >= ERROR_TABLE_BASE_U && errorCode < ERROR_TABLE_BASE_U + 256) {
+       /*
+        * We received a ubik error.  its possible that the server we are
+        * communicating with has a corrupted database or is partitioned
+        * from the rest of the servers and another server might be able
+        * to answer our query.  Therefore, we will retry the request
+        * and force the use of another server.
+        */
+       if (serverp) {
+ 	reqp->tokenIdleErrorServp = serverp;
+ 	reqp->tokenError = errorCode;
+ 	retry = 1;
+       }
      } else if (errorCode == VICECONNBAD || errorCode == VICETOKENDEAD) {
  	cm_ForceNewConnections(serverp);
          if ( timeLeft > 2 )
***************
*** 653,658 ****
--- 692,699 ----
  	    case UAEACCES 	   : s = "UAEACCES";           break;
  	    case ENOENT            : s = "ENOENT"; 	       break;
  	    case UAENOENT          : s = "UAENOENT";           break;
+             case EEXIST            : s = "EEXIST";             break;
+             case UAEEXIST          : s = "UAEEXIST";           break;
  	    case VICECONNBAD	   : s = "VICECONNBAD";	       break;
  	    case VICETOKENDEAD     : s = "VICETOKENDEAD";      break;
              case WSAEWOULDBLOCK    : s = "WSAEWOULDBLOCK";     break;
***************
*** 790,795 ****
--- 831,839 ----
  
      lock_ObtainRead(&cm_serverLock);
      for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+         if (tsrp->status == srv_deleted)
+             continue;
+ 
          tsp = tsrp->server;
          if (reqp->tokenIdleErrorServp) {
              /* 
***************
*** 807,815 ****
              lock_ReleaseRead(&cm_serverLock);
              if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                  allDown = 0;
!                 if (tsrp->status == srv_deleted) {
!                     /* skip this entry.  no longer valid. */;
!                 } else if (tsrp->status == srv_busy) {
                      allOffline = 0;
                      someBusy = 1;
                  } else if (tsrp->status == srv_offline) {
--- 851,857 ----
              lock_ReleaseRead(&cm_serverLock);
              if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                  allDown = 0;
!                 if (tsrp->status == srv_busy) {
                      allOffline = 0;
                      someBusy = 1;
                  } else if (tsrp->status == srv_offline) {
***************
*** 913,922 ****
      }
      if (ucellp->flags & CM_UCELLFLAG_RXKAD) {
          secIndex = 2;
!         if (cryptall) {
!             tcp->cryptlevel = rxkad_crypt;
!         } else {
              tcp->cryptlevel = rxkad_clear;
          }
          secObjp = rxkad_NewClientSecurityObject(tcp->cryptlevel,
                                                  &ucellp->sessionKey, ucellp->kvno,
--- 955,969 ----
      }
      if (ucellp->flags & CM_UCELLFLAG_RXKAD) {
          secIndex = 2;
!         switch (cryptall) {
!         case 0:
              tcp->cryptlevel = rxkad_clear;
+             break;
+         case 2:
+             tcp->cryptlevel = rxkad_auth;
+             break;
+         default:
+             tcp->cryptlevel = rxkad_crypt;
          }
          secObjp = rxkad_NewClientSecurityObject(tcp->cryptlevel,
                                                  &ucellp->sessionKey, ucellp->kvno,
***************
*** 977,983 ****
          serverp->connsp = tcp;
          cm_HoldUser(userp);
          tcp->userp = userp;
!         lock_InitializeMutex(&tcp->mx, "cm_conn_t mutex");
          lock_ObtainMutex(&tcp->mx);
          tcp->serverp = serverp;
          tcp->cryptlevel = rxkad_clear;
--- 1024,1030 ----
          serverp->connsp = tcp;
          cm_HoldUser(userp);
          tcp->userp = userp;
!         lock_InitializeMutex(&tcp->mx, "cm_conn_t mutex", LOCK_HIERARCHY_CONN);
          lock_ObtainMutex(&tcp->mx);
          tcp->serverp = serverp;
          tcp->cryptlevel = rxkad_clear;
***************
*** 993,999 ****
          lock_ObtainMutex(&tcp->mx);
          if ((tcp->flags & CM_CONN_FLAG_FORCE_NEW) ||
              (tcp->ucgen < ucellp->gen) ||
!             (tcp->cryptlevel != (cryptall ? (ucellp->flags & CM_UCELLFLAG_RXKAD ? rxkad_crypt : rxkad_clear) : rxkad_clear)))
          {
              if (tcp->ucgen < ucellp->gen)
                  osi_Log0(afsd_logp, "cm_ConnByServer replace connection due to token update");
--- 1040,1046 ----
          lock_ObtainMutex(&tcp->mx);
          if ((tcp->flags & CM_CONN_FLAG_FORCE_NEW) ||
              (tcp->ucgen < ucellp->gen) ||
!             (tcp->cryptlevel != (ucellp->flags & CM_UCELLFLAG_RXKAD ? (cryptall == 1 ? rxkad_crypt : (cryptall == 2 ? rxkad_auth : rxkad_clear)) : rxkad_clear)))
          {
              if (tcp->ucgen < ucellp->gen)
                  osi_Log0(afsd_logp, "cm_ConnByServer replace connection due to token update");
***************
*** 1031,1036 ****
--- 1078,1085 ----
  
      lock_ObtainRead(&cm_serverLock);
      for (tsrp = *serverspp; tsrp; tsrp=tsrp->next) {
+         if (tsrp->status == srv_deleted)
+             continue;
          tsp = tsrp->server;
          if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
  	    allDown = 0;
***************
*** 1090,1096 ****
  
      *connpp = NULL;
  
!     serverspp = cm_GetVolServers(volp, volid);
  
      code = cm_ConnByMServers(*serverspp, userp, reqp, connpp);
      cm_FreeServerList(serverspp, 0);
--- 1139,1145 ----
  
      *connpp = NULL;
  
!     serverspp = cm_GetVolServers(volp, volid, userp, reqp);
  
      code = cm_ConnByMServers(*serverspp, userp, reqp, connpp);
      cm_FreeServerList(serverspp, 0);
Index: openafs/src/WINNT/afsd/cm_daemon.c
diff -c openafs/src/WINNT/afsd/cm_daemon.c:1.16.4.30 openafs/src/WINNT/afsd/cm_daemon.c:1.16.4.31
*** openafs/src/WINNT/afsd/cm_daemon.c:1.16.4.30	Fri Aug  8 12:46:35 2008
--- openafs/src/WINNT/afsd/cm_daemon.c	Fri Aug 22 14:10:01 2008
***************
*** 601,607 ****
      cm_nDaemons = (nDaemons > CM_MAX_DAEMONS) ? CM_MAX_DAEMONS : nDaemons;
      
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_daemonLock, "cm_daemonLock");
          osi_EndOnce(&once);
  
  	/* creating IP Address Change monitor daemon */
--- 601,608 ----
      cm_nDaemons = (nDaemons > CM_MAX_DAEMONS) ? CM_MAX_DAEMONS : nDaemons;
      
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_daemonLock, "cm_daemonLock", 
!                                LOCK_HIERARCHY_DAEMON_GLOBAL);
          osi_EndOnce(&once);
  
  	/* creating IP Address Change monitor daemon */
Index: openafs/src/WINNT/afsd/cm_dcache.c
diff -c openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.33 openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.34
*** openafs/src/WINNT/afsd/cm_dcache.c:1.30.2.33	Tue Aug  5 11:46:38 2008
--- openafs/src/WINNT/afsd/cm_dcache.c	Fri Aug 22 14:10:01 2008
***************
*** 26,32 ****
  extern void afsi_log(char *pattern, ...);
  #endif
  
- osi_mutex_t cm_bufGetMutex;
  #ifdef AFS_FREELANCE_CLIENT
  extern osi_mutex_t cm_Freelance_Lock;
  #endif
--- 26,31 ----
***************
*** 483,489 ****
  
  int cm_InitDCache(int newFile, long chunkSize, afs_uint64 nbuffers)
  {
-     lock_InitializeMutex(&cm_bufGetMutex, "buf_Get mutex");
      return buf_Init(newFile, &cm_bufOps, nbuffers);
  }
  
--- 482,487 ----
***************
*** 1092,1098 ****
       * sequence at a time.
       */
  
-     // lock_ObtainMutex(&cm_bufGetMutex);
      /* first hold all buffers, since we can't hold any locks in buf_Get */
      while (1) {
          /* stop at chunk boundary */
--- 1090,1095 ----
***************
*** 1105,1111 ****
  
          code = buf_Get(scp, &pageBase, &tbp);
          if (code) {
-             //lock_ReleaseMutex(&cm_bufGetMutex);
              lock_ObtainWrite(&scp->rw);
              cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
              return code;
--- 1102,1107 ----
***************
*** 1121,1128 ****
      /* reserve a chunk's worth of buffers if possible */
      reserving = buf_TryReserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
  
-     // lock_ReleaseMutex(&cm_bufGetMutex);
- 
      pageBase = *offsetp;
      collected = pageBase.LowPart & (cm_chunkSize - 1);
  
--- 1117,1122 ----
Index: openafs/src/WINNT/afsd/cm_dir.c
diff -c openafs/src/WINNT/afsd/cm_dir.c:1.4.4.18 openafs/src/WINNT/afsd/cm_dir.c:1.4.4.20
*** openafs/src/WINNT/afsd/cm_dir.c:1.4.4.18	Fri Jul 11 18:27:01 2008
--- openafs/src/WINNT/afsd/cm_dir.c	Tue Sep 16 07:47:47 2008
***************
*** 98,104 ****
  cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * buffer, int flags);
  
  static long
! cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked);
  
  static long
  cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified);
--- 98,104 ----
  cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * buffer, int flags);
  
  static long
! cm_DirCheckStatus(cm_dirOp_t * op, int locked);
  
  static long
  cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified);
***************
*** 116,121 ****
--- 116,123 ----
  static long
  cm_DirFreeBlobs(cm_dirOp_t * op, int firstblob, int nblobs);
  
+ static long
+ cm_DirPrefetchBuffers(cm_dirOp_t * op);
  
  /* compute how many 32 byte entries an AFS 3 dir requires for storing
   * the specified name.
***************
*** 393,398 ****
--- 395,403 ----
                  dhpModified = TRUE;
  	    }
  
+             /* the create flag is not set for the GetPage call below
+                since the page should have been added if necessary
+                above. */
              code = cm_DirGetPage(op, i, &pagebuf, &pp);
              if (code) {
                  cm_DirReleasePage(op, &dhpbuf, dhpModified);
***************
*** 603,608 ****
--- 608,621 ----
      code = cm_DirFindItem(op, entry,
                            &itembuf, &firstitem,
                            &pibuf, &previtem);
+ 
+     if (code == CM_ERROR_NOTINCACHE) {
+         code = cm_DirPrefetchBuffers(op);
+         if (code == 0)
+             code = cm_DirFindItem(op, entry, &itembuf, &firstitem,
+                                   &pibuf, &previtem);
+     }
+ 
      if (code != 0) {
          dir_lookup_misses++;
          code = ENOENT;
***************
*** 1121,1127 ****
  }
  
  /* Check if it is safe for us to perform local directory updates.
!    Called with scp->rw unlocked. */
  int
  cm_CheckDirOpForSingleChange(cm_dirOp_t * op)
  {
--- 1134,1140 ----
  }
  
  /* Check if it is safe for us to perform local directory updates.
!    Called with op->scp->rw unlocked. */
  int
  cm_CheckDirOpForSingleChange(cm_dirOp_t * op)
  {
***************
*** 1194,1199 ****
--- 1207,1213 ----
           * and update the dataVersion for each. */
          lock_ObtainWrite(&op->scp->rw);
          code = buf_ForceDataVersion(op->scp, op->dataVersion, op->newDataVersion);
+         op->scp->flags |= CM_SCACHEFLAG_LOCAL;
          lock_ReleaseWrite(&op->scp->rw);
      }
  
***************
*** 1271,1285 ****
                           CM_SCACHESYNC_BUFLOCKED);
  
          if (code == 0 && bufferp->dataVersion != op->dataVersion) {
!             osi_Log2(afsd_logp, "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %d. needs %d", 
!                      bufferp->dataVersion, op->dataVersion);
  
!             cm_SyncOpDone(op->scp, bufferp,
!                           CM_SCACHESYNC_NEEDCALLBACK |
!                          (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
!                           CM_SCACHESYNC_BUFLOCKED);
! 
!             code = CM_ERROR_INVAL;
          }
  
          lock_ReleaseWrite(&op->scp->rw);
--- 1285,1300 ----
                           CM_SCACHESYNC_BUFLOCKED);
  
          if (code == 0 && bufferp->dataVersion != op->dataVersion) {
!                 osi_Log2(afsd_logp,
!                          "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %d. needs %d", 
!                          bufferp->dataVersion, op->dataVersion);
! 
!                 cm_SyncOpDone(op->scp, bufferp,
!                               CM_SCACHESYNC_NEEDCALLBACK |
!                               (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
!                               CM_SCACHESYNC_BUFLOCKED);
  
!             code = CM_ERROR_NOTINCACHE;
          }
  
          lock_ReleaseWrite(&op->scp->rw);
***************
*** 1441,1455 ****
       scp->rw may be released
   */
  static long
! cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked)
  {
      long code;
  
!     if (!locked)
          lock_ObtainWrite(&op->scp->rw);
      code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (!locked)
          lock_ReleaseWrite(&op->scp->rw);
  
      osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x",
--- 1456,1470 ----
       scp->rw may be released
   */
  static long
! cm_DirCheckStatus(cm_dirOp_t * op, int scp_locked)
  {
      long code;
  
!     if (!scp_locked)
          lock_ObtainWrite(&op->scp->rw);
      code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
!     if (!scp_locked)
          lock_ReleaseWrite(&op->scp->rw);
  
      osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x",
***************
*** 1458,1463 ****
--- 1473,1564 ----
      return code;
  }
  
+ /* Attempt to prefetch all the buffers for this operation.
+ 
+    Called with scp->rw unlocked
+  */
+ static long
+ cm_DirPrefetchBuffers(cm_dirOp_t * op)
+ {
+     long code = 0;
+     osi_hyper_t offset;
+     cm_buf_t *bufferp = NULL;
+ 
+     osi_Log1(afsd_logp, "cm_DirPrefetchBuffers for op 0x%p", op);
+ 
+     /* prefetching is only done on read operations where we don't
+        expect the data version to change. */
+     if (op->dataVersion != op->newDataVersion) {
+         osi_Log0(afsd_logp, "Skipping prefetch for write operation.");
+         return CM_ERROR_INVAL;
+     }
+ 
+     lock_ObtainWrite(&op->scp->rw);
+ 
+     /* When we are prefetching a file, we first flush out any of its
+        contents just to make sure that we don't end up with buffers
+        that was locally modified. */
+ 
+     if (op->scp->flags & CM_SCACHEFLAG_LOCAL) {
+         lock_ReleaseWrite(&op->scp->rw);
+         code = cm_FlushFile(op->scp, op->userp, &op->req);
+         if (code != 0)
+             return code;
+         lock_ObtainWrite(&op->scp->rw);
+     }
+ 
+     offset = ConvertLongToLargeInteger(0);
+     while (LargeIntegerLessThan(offset, op->scp->length)) {
+         osi_Log2(afsd_logp, "Trying prefetch for offset %08x:%08x",
+                  offset.HighPart, offset.LowPart);
+         lock_ReleaseWrite(&op->scp->rw);
+ 
+         code = buf_Get(op->scp, &offset, &bufferp);
+ 
+         lock_ObtainWrite(&op->scp->rw);
+ 
+         if (code)
+             break;
+ 
+         while (1) {
+ 
+             code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP,
+                              CM_SCACHESYNC_NEEDCALLBACK |
+                              (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ));
+ 
+             if (code)
+                 break;
+ 
+             cm_SyncOpDone(op->scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK |
+                           (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ));
+ 
+             if (cm_HaveBuffer(op->scp, bufferp, 0))
+                 break;
+ 
+             code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req);
+             if (code)
+                 break;
+         }
+ 
+         if (code)
+             break;
+ 
+         if (bufferp) {
+             buf_Release(bufferp);
+             bufferp = NULL;
+         }
+ 
+         offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(cm_data.buf_blockSize));
+     }
+ 
+  done:
+     lock_ReleaseWrite(&op->scp->rw);
+ 
+     osi_Log1(afsd_logp, "cm_DirPrefetchBuffers returning code 0x%x", code);
+ 
+     return code;
+ }
+ 
  /* Release a directory buffer that was obtained via a call to
     cm_DirGetPage() or any other function that returns a locked, held,
     directory page buffer.
***************
*** 1497,1502 ****
--- 1598,1606 ----
     released and a new buffer returned that contains the requested
     page.
  
+    If the specified page exists beyond the EOF for the scp, a new
+    buffer will be allocated only if create is set to TRUE.
+ 
     Note: If a buffer is specified on entry via bufferpp, it is assumed
     that the buffer is unmodified.  If the buffer is modified, it
     should be released via cm_DirReleasePage().
***************
*** 1577,1626 ****
              bufferp = NULL;
              goto _exit;
          }
- 
- #if 0
-         /* The code below is for making sure the buffer contains
-            current data.  This is a bad idea, since the whole point of
-            doing directory updates locally is to avoid fetching all
-            the data from the server. */
-         while (1) {
-             lock_ObtainWrite(&op->scp->rw);
-             code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP,
-                              CM_SCACHESYNC_NEEDCALLBACK |
-                              CM_SCACHESYNC_READ |
-                              CM_SCACHESYNC_BUFLOCKED);
- 
-             if (code) {
-                 lock_ReleaseWrite(&op->scp->rw);
-                 break;
-             }
- 
-             cm_SyncOpDone(op->scp, bufferp,
-                           CM_SCACHESYNC_NEEDCALLBACK |
-                           CM_SCACHESYNC_READ |
-                           CM_SCACHESYNC_BUFLOCKED);
- 
-             if (cm_HaveBuffer(op->scp, bufferp, 1)) {
-                 lock_ReleaseWrite(&op->scp->rw);
-                 break;
-             }
- 
-             lock_ReleaseMutex(&bufferp->mx);
-             code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req);
-             lock_ReleaseWrite(&op->scp->rw);
-             lock_ObtainMutex(&bufferp->mx);
- 
-             if (code)
-                 break;
-         }
- 
-         if (code) {
-             cm_DirOpDelBuffer(op, bufferp, 0);
-             buf_Release(bufferp);
-             bufferp = NULL;
-             goto _exit;
-         }
- #endif
      }
  
   _has_buffer:
--- 1681,1686 ----
Index: openafs/src/WINNT/afsd/cm_dnlc.c
diff -c openafs/src/WINNT/afsd/cm_dnlc.c:1.10.4.9 openafs/src/WINNT/afsd/cm_dnlc.c:1.10.4.10
*** openafs/src/WINNT/afsd/cm_dnlc.c:1.10.4.9	Thu Jun 26 12:38:29 2008
--- openafs/src/WINNT/afsd/cm_dnlc.c	Fri Aug 22 14:10:01 2008
***************
*** 672,678 ****
  
      memset (&dnlcstats, 0, sizeof(dnlcstats));
  
!     lock_InitializeRWLock(&cm_dnlcLock, "cm_dnlcLock");
      if ( newFile ) {
          lock_ObtainWrite(&cm_dnlcLock);
          cm_data.ncfreelist = (cm_nc_t *) 0;
--- 672,678 ----
  
      memset (&dnlcstats, 0, sizeof(dnlcstats));
  
!     lock_InitializeRWLock(&cm_dnlcLock, "cm_dnlcLock", LOCK_HIERARCHY_DNLC_GLOBAL);
      if ( newFile ) {
          lock_ObtainWrite(&cm_dnlcLock);
          cm_data.ncfreelist = (cm_nc_t *) 0;
Index: openafs/src/WINNT/afsd/cm_freelance.c
diff -c openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.16 openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.17
*** openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.16	Fri Aug 15 16:19:06 2008
--- openafs/src/WINNT/afsd/cm_freelance.c	Fri Aug 22 14:10:01 2008
***************
*** 139,145 ****
      thread_t phandle;
      int lpid;
  
!     lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock");
  
      // yj: first we make a call to cm_initLocalMountPoints
      // to read all the local mount points from the registry
--- 139,145 ----
      thread_t phandle;
      int lpid;
  
!     lock_InitializeMutex(&cm_Freelance_Lock, "Freelance Lock", LOCK_HIERARCHY_FREELANCE_GLOBAL);
  
      // yj: first we make a call to cm_initLocalMountPoints
      // to read all the local mount points from the registry
***************
*** 391,397 ****
              if (scp != cm_data.rootSCachep && cm_FidCmp(&scp->fid, &aFid) == 0) {
                  // mark the scp to be reused
                  cm_HoldSCacheNoLock(scp);
!                 lock_ReleaseWrite(&cm_Freelance_Lock);
                  lock_ReleaseWrite(&cm_scacheLock);
                  lock_ObtainWrite(&scp->rw);
                  cm_DiscardSCache(scp);
--- 391,397 ----
              if (scp != cm_data.rootSCachep && cm_FidCmp(&scp->fid, &aFid) == 0) {
                  // mark the scp to be reused
                  cm_HoldSCacheNoLock(scp);
!                 lock_ReleaseMutex(&cm_Freelance_Lock);
                  lock_ReleaseWrite(&cm_scacheLock);
                  lock_ObtainWrite(&scp->rw);
                  cm_DiscardSCache(scp);
Index: openafs/src/WINNT/afsd/cm_ioctl.c
diff -c openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.55 openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.62
*** openafs/src/WINNT/afsd/cm_ioctl.c:1.73.2.55	Mon Aug 11 19:56:14 2008
--- openafs/src/WINNT/afsd/cm_ioctl.c	Wed Sep 24 18:58:32 2008
***************
*** 60,66 ****
  
  void cm_InitIoctl(void)
  {
!     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
  }
  
  /* 
--- 60,67 ----
  
  void cm_InitIoctl(void)
  {
!     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock",
!                           LOCK_HIERARCHY_AFSDBSBMT_GLOBAL);
  }
  
  /* 
***************
*** 103,108 ****
--- 104,111 ----
          
      lock_ObtainWrite(&scp->rw);
      cm_DiscardSCache(scp);
+     if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
+         cm_ResetSCacheDirectory(scp);
      lock_ReleaseWrite(&scp->rw);
  
      osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
***************
*** 905,911 ****
  afs_int32 
  cm_IoctlWhereIs(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
      cm_serverRef_t **tsrpp, *current;
--- 908,914 ----
  afs_int32 
  cm_IoctlWhereIs(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *scp, cm_req_t *reqp)
  {
!     afs_int32 code = 0;
      cm_cell_t *cellp;
      cm_volume_t *tvp;
      cm_serverRef_t **tsrpp, *current;
***************
*** 949,964 ****
  	
          cp = ioctlp->outDatap;
          
!         tsrpp = cm_GetVolServers(tvp, volume);
!         lock_ObtainRead(&cm_serverLock);
!         for (current = *tsrpp; current; current = current->next) {
!             tsp = current->server;
!             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
!             cp += sizeof(long);
          }
-         lock_ReleaseRead(&cm_serverLock);
-         cm_FreeServerList(tsrpp, 0);
- 
          /* still room for terminating NULL, add it on */
          volume = 0;	/* reuse vbl */
          memcpy(cp, (char *)&volume, sizeof(long));
--- 952,970 ----
  	
          cp = ioctlp->outDatap;
          
!         tsrpp = cm_GetVolServers(tvp, volume, userp, reqp);
!         if (tsrpp == NULL) {
!             code = CM_ERROR_NOSUCHVOLUME;
!         } else {
!             lock_ObtainRead(&cm_serverLock);
!             for (current = *tsrpp; current; current = current->next) {
!                 tsp = current->server;
!                 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
!                 cp += sizeof(long);
!             }
!             lock_ReleaseRead(&cm_serverLock);
!             cm_FreeServerList(tsrpp, 0);
          }
          /* still room for terminating NULL, add it on */
          volume = 0;	/* reuse vbl */
          memcpy(cp, (char *)&volume, sizeof(long));
***************
*** 967,973 ****
          ioctlp->outDatap = cp;
          cm_PutVolume(tvp);
      }
!     return 0;
  }       
  
  /* 
--- 973,979 ----
          ioctlp->outDatap = cp;
          cm_PutVolume(tvp);
      }
!     return code;
  }       
  
  /* 
***************
*** 984,990 ****
      clientchar_t *cp;
  
      cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
      if (code) 
          goto done_2;
  
--- 990,997 ----
      clientchar_t *cp;
  
      cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
! 
!     code = cm_Lookup(dscp, cp[0] ? cp : L".", CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
      if (code) 
          goto done_2;
  
***************
*** 1039,1045 ****
  
      cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
  
!     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
          
      /* if something went wrong, bail out now */
      if (code)
--- 1046,1052 ----
  
      cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
  
!     code = cm_Lookup(dscp, cp[0] ? cp : L".", CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
          
      /* if something went wrong, bail out now */
      if (code)
***************
*** 1406,1415 ****
      for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
      {
          afs_int32 code;
! 	lock_ObtainMutex(&cp->mx);
          /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
          cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
          cp->vlServersp = NULL;
          rock.cellp = cp;
          rock.flags = 0;
          code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, &rock);
--- 1413,1424 ----
      for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
      {
          afs_int32 code;
! 
          /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
          cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
          cp->vlServersp = NULL;
+         lock_ReleaseWrite(&cm_cellLock);
+ 
          rock.cellp = cp;
          rock.flags = 0;
          code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, &rock);
***************
*** 1419,1444 ****
                  int ttl;
                  code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, &rock);
                  if ( code == 0 ) { /* got cell from DNS */
                      cp->flags |= CM_CELLFLAG_DNS;
                      cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
                      cp->timeout = time(0) + ttl;
                  }
              }
          } 
          else {
              cp->flags &= ~CM_CELLFLAG_DNS;
          }
  #endif /* AFS_AFSDB_ENV */
          if (code) {
              cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
          }
          else {
              cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
              cm_RandomizeServer(&cp->vlServersp);
          }
- 	lock_ReleaseMutex(&cp->mx);
      }
-     
      lock_ReleaseWrite(&cm_cellLock);
      return 0;       
  }
--- 1428,1461 ----
                  int ttl;
                  code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, &rock);
                  if ( code == 0 ) { /* got cell from DNS */
+                     lock_ObtainMutex(&cp->mx);
                      cp->flags |= CM_CELLFLAG_DNS;
                      cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
                      cp->timeout = time(0) + ttl;
+                     lock_ReleaseMutex(&cp->mx);
                  }
              }
          } 
          else {
+             lock_ObtainMutex(&cp->mx);
              cp->flags &= ~CM_CELLFLAG_DNS;
+             lock_ReleaseMutex(&cp->mx);
          }
  #endif /* AFS_AFSDB_ENV */
          if (code) {
+             lock_ObtainMutex(&cp->mx);
              cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
+             lock_ReleaseMutex(&cp->mx);
+             lock_ObtainWrite(&cm_cellLock);
          }
          else {
+             lock_ObtainMutex(&cp->mx);
              cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
+             lock_ReleaseMutex(&cp->mx);
+             lock_ObtainWrite(&cm_cellLock);
              cm_RandomizeServer(&cp->vlServersp);
          }
      }
      lock_ReleaseWrite(&cm_cellLock);
      return 0;       
  }
***************
*** 1943,1949 ****
      cp = ioctlp->inDatap;
  
      clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
      free(clientp);
      if (code) 
          return code;
--- 1960,1966 ----
      cp = ioctlp->inDatap;
  
      clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp[0] ? clientp : L".", CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
      free(clientp);
      if (code) 
          return code;
***************
*** 1959,1974 ****
      code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, reqp);
      cm_ReleaseSCache(scp);
      if (code == 0) {
          cp = ioctlp->outDatap;
          if (newRootScp != NULL) {
              StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), cm_mountRoot);
              StringCbCatA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), "/");
              cp += strlen(cp);
          }
!         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), spacep->data);
          cp += strlen(cp) + 1;
          ioctlp->outDatap = cp;
          cm_FreeSpace(spacep);
          if (newRootScp != NULL)
              cm_ReleaseSCache(newRootScp);
          code = 0;
--- 1976,1995 ----
      code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, reqp);
      cm_ReleaseSCache(scp);
      if (code == 0) {
+         char * linkstr;
          cp = ioctlp->outDatap;
          if (newRootScp != NULL) {
              StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), cm_mountRoot);
              StringCbCatA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), "/");
              cp += strlen(cp);
          }
! 
!         linkstr = cm_ClientStringToFsStringAlloc(spacep->wdata, -1, NULL);
!         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), linkstr);
          cp += strlen(cp) + 1;
          ioctlp->outDatap = cp;
          cm_FreeSpace(spacep);
+         free(linkstr);
          if (newRootScp != NULL)
              cm_ReleaseSCache(newRootScp);
          code = 0;
***************
*** 2009,2015 ****
      osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
  
      clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
      free(clientp);
      if (code)
          return code;
--- 2030,2036 ----
      osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
  
      clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp[0] ? clientp : L".", CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
      free(clientp);
      if (code)
          return code;
***************
*** 2046,2052 ****
      cp = ioctlp->inDatap;
  
      clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
  
      /* if something went wrong, bail out now */
      if (code)
--- 2067,2073 ----
      cp = ioctlp->inDatap;
  
      clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
!     code = cm_Lookup(dscp, clientp[0] ? clientp : L".", CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
  
      /* if something went wrong, bail out now */
      if (code)
***************
*** 2807,2814 ****
      memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
  
      if (c != cryptall) {
! 	if (cryptall)
              LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
  	else
              LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
      }
--- 2828,2837 ----
      memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
  
      if (c != cryptall) {
! 	if (cryptall == 1)
              LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
+ 	else if (cryptall == 2)
+             LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_AUTH);
  	else
              LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
      }
***************
*** 3029,3034 ****
--- 3052,3059 ----
  
      lock_ObtainRead(&cm_serverLock);
      for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+         if (tsrp->status == srv_deleted)
+             continue;
          if (tsp = tsrp->server) {
              cm_GetServerNoLock(tsp);
              lock_ReleaseRead(&cm_serverLock);
Index: openafs/src/WINNT/afsd/cm_memmap.h
diff -c openafs/src/WINNT/afsd/cm_memmap.h:1.3.4.11 openafs/src/WINNT/afsd/cm_memmap.h:1.3.4.13
*** openafs/src/WINNT/afsd/cm_memmap.h:1.3.4.11	Mon Apr 21 11:36:49 2008
--- openafs/src/WINNT/afsd/cm_memmap.h	Tue Sep 16 07:47:47 2008
***************
*** 10,16 ****
  #ifndef CM_MEMMAP_H
  #define CM_MEMMAP_H 1
  
! #define CM_CONFIG_DATA_VERSION  3
  #define CM_CONFIG_DATA_MAGIC            ('A' | 'F'<<8 | 'S'<<16 | CM_CONFIG_DATA_VERSION<<24)
  
  typedef struct cm_config_data {
--- 10,16 ----
  #ifndef CM_MEMMAP_H
  #define CM_MEMMAP_H 1
  
! #define CM_CONFIG_DATA_VERSION  5
  #define CM_CONFIG_DATA_MAGIC            ('A' | 'F'<<8 | 'S'<<16 | CM_CONFIG_DATA_VERSION<<24)
  
  typedef struct cm_config_data {
***************
*** 39,44 ****
--- 39,45 ----
      afs_uint32          maxVolumes;
  
      cm_cell_t	*       allCellsp;
+     cm_cell_t   *       freeCellsp;
      afs_uint32          currentCells;
      afs_uint32          maxCells;
  
Index: openafs/src/WINNT/afsd/cm_rpc.c
diff -c openafs/src/WINNT/afsd/cm_rpc.c:1.7.8.1 openafs/src/WINNT/afsd/cm_rpc.c:1.7.8.2
*** openafs/src/WINNT/afsd/cm_rpc.c:1.7.8.1	Thu Jun 26 10:38:24 2008
--- openafs/src/WINNT/afsd/cm_rpc.c	Fri Aug 22 14:10:01 2008
***************
*** 209,215 ****
      ULONG listenThreadID = 0;
      char * name = "afsd_rpc_ShutdownEvent";
  
!     lock_InitializeMutex(&tokenEventLock, "token event lock");
  
      rpc_ShutdownEvent = thrd_CreateEvent(NULL, FALSE, FALSE, name);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
--- 209,216 ----
      ULONG listenThreadID = 0;
      char * name = "afsd_rpc_ShutdownEvent";
  
!     lock_InitializeMutex(&tokenEventLock, "token event lock",
!                           LOCK_HIERARCHY_TOKEN_EVENT_GLOBAL);
  
      rpc_ShutdownEvent = thrd_CreateEvent(NULL, FALSE, FALSE, name);
      if ( GetLastError() == ERROR_ALREADY_EXISTS )
Index: openafs/src/WINNT/afsd/cm_scache.c
diff -c openafs/src/WINNT/afsd/cm_scache.c:1.35.2.84 openafs/src/WINNT/afsd/cm_scache.c:1.35.2.89
*** openafs/src/WINNT/afsd/cm_scache.c:1.35.2.84	Thu Aug 14 16:21:27 2008
--- openafs/src/WINNT/afsd/cm_scache.c	Tue Sep 16 07:47:47 2008
***************
*** 75,84 ****
      }
  }
  
! /* called with cm_scacheLock write-locked; recycles an existing scp. 
!  *
!  * this function ignores all of the locking hierarchy.  
!  */
  long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
  {
      if (scp->refCount != 0) {
--- 75,99 ----
      }
  }
  
! /* called with cm_scacheLock and scp write-locked */
! void cm_ResetSCacheDirectory(cm_scache_t *scp)
! {
! #ifdef USE_BPLUS
!     /* destroy directory Bplus Tree */
!     if (scp->dirBplus) {
!         LARGE_INTEGER start, end;
!         QueryPerformanceCounter(&start);
!         bplus_free_tree++;
!         freeBtree(scp->dirBplus);
!         scp->dirBplus = NULL;
!         QueryPerformanceCounter(&end);
! 
!         bplus_free_time += (end.QuadPart - start.QuadPart);
!     }
! #endif
! }
! 
! /* called with cm_scacheLock and scp write-locked; recycles an existing scp. */
  long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
  {
      if (scp->refCount != 0) {
***************
*** 93,101 ****
  	return -1;
      }
  
-     lock_ObtainWrite(&scp->rw);
      cm_RemoveSCacheFromHashTable(scp);
-     lock_ReleaseWrite(&scp->rw);
  
  #if 0
      if (flags & CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS) {
--- 108,114 ----
***************
*** 209,233 ****
       */
      cm_FreeAllACLEnts(scp);
  
! #ifdef USE_BPLUS
!     /* destroy directory Bplus Tree */
!     if (scp->dirBplus) {
!         LARGE_INTEGER start, end;
!         QueryPerformanceCounter(&start);
!         bplus_free_tree++;
!         freeBtree(scp->dirBplus);
!         scp->dirBplus = NULL;
!         QueryPerformanceCounter(&end);
! 
!         bplus_free_time += (end.QuadPart - start.QuadPart);
!     }
! #endif
      return 0;
  }
  
  
! /* called with cm_scacheLock write-locked; find a vnode to recycle.
   * Can allocate a new one if desperate, or if below quota (cm_data.maxSCaches).
   */
  cm_scache_t *cm_GetNewSCache(void)
  {
--- 222,236 ----
       */
      cm_FreeAllACLEnts(scp);
  
!     cm_ResetSCacheDirectory(scp);
      return 0;
  }
  
  
! /* 
!  * called with cm_scacheLock write-locked; find a vnode to recycle.
   * Can allocate a new one if desperate, or if below quota (cm_data.maxSCaches).
+  * returns scp->mx held.
   */
  cm_scache_t *cm_GetNewSCache(void)
  {
***************
*** 246,251 ****
--- 249,257 ----
  
  	if (scp->refCount == 0) {
  	    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+                 if (!lock_TryWrite(&scp->rw))
+                     continue;
+ 
  		osi_Log1(afsd_logp, "GetNewSCache attempting to recycle deleted scp 0x%x", scp);
  		if (!cm_RecycleSCache(scp, CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS)) {
  
***************
*** 258,265 ****
--- 264,275 ----
  		    /* and we're done */
  		    return scp;
  		} 
+                 lock_ReleaseWrite(&scp->rw);
  		osi_Log1(afsd_logp, "GetNewSCache recycled failed scp 0x%x", scp);
  	    } else if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
+                 if (!lock_TryWrite(&scp->rw))
+                     continue;
+ 
  		/* we found an entry, so return it */
  		/* now remove from the LRU queue and put it back at the
  		* head of the LRU queue.
***************
*** 287,292 ****
--- 297,305 ----
               * we must not recycle the scp. */
              if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
                  if (!buf_DirtyBuffersExist(&scp->fid)) {
+                     if (!lock_TryWrite(&scp->rw))
+                         continue;
+ 
                      if (!cm_RecycleSCache(scp, 0)) {
                          /* we found an entry, so return it */
                          /* now remove from the LRU queue and put it back at the
***************
*** 297,302 ****
--- 310,316 ----
                          /* and we're done */
                          return scp;
                      }
+                     lock_ReleaseWrite(&scp->rw);
                  } else {
                      osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%x", scp);
                  }
***************
*** 315,324 ****
                  "invalid cm_scache_t address");
      memset(scp, 0, sizeof(cm_scache_t));
      scp->magic = CM_SCACHE_MAGIC;
!     lock_InitializeRWLock(&scp->rw, "cm_scache_t rw");
!     lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
  #ifdef USE_BPLUS
!     lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
  #endif
      scp->serverLock = -1;
  
--- 329,339 ----
                  "invalid cm_scache_t address");
      memset(scp, 0, sizeof(cm_scache_t));
      scp->magic = CM_SCACHE_MAGIC;
!     lock_InitializeRWLock(&scp->rw, "cm_scache_t rw", LOCK_HIERARCHY_SCACHE);
!     osi_assertx(lock_TryWrite(&scp->rw), "cm_scache_t rw held after allocation");
!     lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock", LOCK_HIERARCHY_SCACHE_BUFCREATE);
  #ifdef USE_BPLUS
!     lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock", LOCK_HIERARCHY_SCACHE_DIRLOCK);
  #endif
      scp->serverLock = -1;
  
***************
*** 371,377 ****
          cm_data.fakeSCache.linkCount = 1;
          cm_data.fakeSCache.refCount = 1;
      }
!     lock_InitializeRWLock(&cm_data.fakeSCache.rw, "cm_scache_t rw");
  }
  
  long
--- 386,392 ----
          cm_data.fakeSCache.linkCount = 1;
          cm_data.fakeSCache.refCount = 1;
      }
!     lock_InitializeRWLock(&cm_data.fakeSCache.rw, "cm_scache_t rw", LOCK_HIERARCHY_SCACHE);
  }
  
  long
***************
*** 523,529 ****
--- 538,546 ----
      for ( scp = cm_data.allSCachesp; scp;
            scp = scp->allNextp ) {
          if (scp->randomACLp) {
+             lock_ReleaseWrite(&cm_scacheLock);
              lock_ObtainWrite(&scp->rw);
+             lock_ObtainWrite(&cm_scacheLock);
              cm_FreeAllACLEnts(scp);
              lock_ReleaseWrite(&scp->rw);
          }
***************
*** 557,563 ****
      static osi_once_t once;
          
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_scacheLock, "cm_scacheLock");
          if ( newFile ) {
              memset(cm_data.scacheHashTablep, 0, sizeof(cm_scache_t *) * cm_data.scacheHashTableSize);
              cm_data.allSCachesp = NULL;
--- 574,580 ----
      static osi_once_t once;
          
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_scacheLock, "cm_scacheLock", LOCK_HIERARCHY_SCACHE_GLOBAL);
          if ( newFile ) {
              memset(cm_data.scacheHashTablep, 0, sizeof(cm_scache_t *) * cm_data.scacheHashTableSize);
              cm_data.allSCachesp = NULL;
***************
*** 569,578 ****
  
              for ( scp = cm_data.allSCachesp; scp;
                    scp = scp->allNextp ) {
!                 lock_InitializeRWLock(&scp->rw, "cm_scache_t rw");
!                 lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
  #ifdef USE_BPLUS
!                 lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
  #endif
                  scp->cbServerp = NULL;
                  scp->cbExpires = 0;
--- 586,595 ----
  
              for ( scp = cm_data.allSCachesp; scp;
                    scp = scp->allNextp ) {
!                 lock_InitializeRWLock(&scp->rw, "cm_scache_t rw", LOCK_HIERARCHY_SCACHE);
!                 lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock", LOCK_HIERARCHY_SCACHE_BUFCREATE);
  #ifdef USE_BPLUS
!                 lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock", LOCK_HIERARCHY_SCACHE_DIRLOCK);
  #endif
                  scp->cbServerp = NULL;
                  scp->cbExpires = 0;
***************
*** 667,674 ****
      for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
          if (cm_FidCmp(fidp, &scp->fid) == 0) {
  #ifdef DEBUG_REFCOUNT
! 	    afsi_log("%s:%d cm_GetSCache (1) outScpp 0x%p ref %d", file, line, scp, scp->refCount);
! 	    osi_Log1(afsd_logp,"cm_GetSCache (1) outScpp 0x%p", scp);
  #endif
  #ifdef AFS_FREELANCE_CLIENT
              if (cm_freelanceEnabled && special && 
--- 684,691 ----
      for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
          if (cm_FidCmp(fidp, &scp->fid) == 0) {
  #ifdef DEBUG_REFCOUNT
! 	    afsi_log("%s:%d cm_GetSCache (1) scp 0x%p ref %d", file, line, scp, scp->refCount);
! 	    osi_Log1(afsd_logp,"cm_GetSCache (1) scp 0x%p", scp);
  #endif
  #ifdef AFS_FREELANCE_CLIENT
              if (cm_freelanceEnabled && special && 
***************
*** 726,749 ****
          }
          lock_ReleaseMutex(&cm_Freelance_Lock);
          lock_ObtainWrite(&cm_scacheLock);
!         if (scp == NULL)
!             scp = cm_GetNewSCache();
! 	if (scp == NULL) {
! 	    osi_Log0(afsd_logp,"cm_GetSCache unable to obtain *new* scache entry");
              lock_ReleaseWrite(&cm_scacheLock);
! 	    return CM_ERROR_WOULDBLOCK;
! 	}
! 
! #if not_too_dangerous
! 	/* dropping the cm_scacheLock allows more than one thread
! 	 * to obtain the same cm_scache_t from the LRU list.  Since
! 	 * the refCount is known to be zero at this point we have to
! 	 * assume that no one else is using the one this is returned.
! 	 */
! 	lock_ReleaseWrite(&cm_scacheLock);
! 	lock_ObtainWrite(&scp->rw);
! 	lock_ObtainWrite(&cm_scacheLock);
! #endif
          scp->fid = *fidp;
          scp->dotdotFid.cell=AFS_FAKE_ROOT_CELL_ID;
          scp->dotdotFid.volume=AFS_FAKE_ROOT_VOL_ID;
--- 743,760 ----
          }
          lock_ReleaseMutex(&cm_Freelance_Lock);
          lock_ObtainWrite(&cm_scacheLock);
!         if (scp == NULL) {
!             scp = cm_GetNewSCache();    /* returns scp->rw held */
!             if (scp == NULL) {
!                 osi_Log0(afsd_logp,"cm_GetSCache unable to obtain *new* scache entry");
!                 lock_ReleaseWrite(&cm_scacheLock);
!                 return CM_ERROR_WOULDBLOCK;
!             }
!         } else {
              lock_ReleaseWrite(&cm_scacheLock);
!             lock_ObtainWrite(&scp->rw);
!             lock_ObtainWrite(&cm_scacheLock);
!         }
          scp->fid = *fidp;
          scp->dotdotFid.cell=AFS_FAKE_ROOT_CELL_ID;
          scp->dotdotFid.volume=AFS_FAKE_ROOT_VOL_ID;
***************
*** 771,784 ****
          scp->dataVersion=cm_data.fakeDirVersion;
          scp->bufDataVersionLow=cm_data.fakeDirVersion;
          scp->lockDataVersion=-1; /* no lock yet */
! #if not_too_dangerous
! 	lock_ReleaseWrite(&scp->rw);
! #endif
! 	*outScpp = scp;
          lock_ReleaseWrite(&cm_scacheLock);
  #ifdef DEBUG_REFCOUNT
! 	afsi_log("%s:%d cm_GetSCache (2) outScpp 0x%p ref %d", file, line, scp, scp->refCount);
! 	osi_Log1(afsd_logp,"cm_GetSCache (2) outScpp 0x%p", scp);
  #endif
          return 0;
      }
--- 782,793 ----
          scp->dataVersion=cm_data.fakeDirVersion;
          scp->bufDataVersionLow=cm_data.fakeDirVersion;
          scp->lockDataVersion=-1; /* no lock yet */
!         lock_ReleaseWrite(&scp->rw);
          lock_ReleaseWrite(&cm_scacheLock);
+ 	*outScpp = scp;
  #ifdef DEBUG_REFCOUNT
! 	afsi_log("%s:%d cm_GetSCache (2) scp 0x%p ref %d", file, line, scp, scp->refCount);
! 	osi_Log1(afsd_logp,"cm_GetSCache (2) scp 0x%p", scp);
  #endif
          return 0;
      }
***************
*** 804,811 ****
      for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
          if (cm_FidCmp(fidp, &scp->fid) == 0) {
  #ifdef DEBUG_REFCOUNT
! 	    afsi_log("%s:%d cm_GetSCache (3) outScpp 0x%p ref %d", file, line, scp, scp->refCount);
! 	    osi_Log1(afsd_logp,"cm_GetSCache (3) outScpp 0x%p", scp);
  #endif
              cm_HoldSCacheNoLock(scp);
              cm_AdjustScacheLRU(scp);
--- 813,820 ----
      for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
          if (cm_FidCmp(fidp, &scp->fid) == 0) {
  #ifdef DEBUG_REFCOUNT
! 	    afsi_log("%s:%d cm_GetSCache (3) scp 0x%p ref %d", file, line, scp, scp->refCount);
! 	    osi_Log1(afsd_logp,"cm_GetSCache (3) scp 0x%p", scp);
  #endif
              cm_HoldSCacheNoLock(scp);
              cm_AdjustScacheLRU(scp);
***************
*** 818,824 ****
      }
          
      /* now, if we don't have the fid, recycle something */
!     scp = cm_GetNewSCache();
      if (scp == NULL) {
  	osi_Log0(afsd_logp,"cm_GetNewSCache unable to obtain *new* scache entry");
  	lock_ReleaseWrite(&cm_scacheLock);
--- 827,833 ----
      }
          
      /* now, if we don't have the fid, recycle something */
!     scp = cm_GetNewSCache();    /* returns scp->rw held */
      if (scp == NULL) {
  	osi_Log0(afsd_logp,"cm_GetNewSCache unable to obtain *new* scache entry");
  	lock_ReleaseWrite(&cm_scacheLock);
***************
*** 826,845 ****
  	    cm_PutVolume(volp);
  	return CM_ERROR_WOULDBLOCK;
      }
!     osi_Log2(afsd_logp,"cm_GetNewSCache returns scp 0x%x flags 0x%x", scp, scp->flags);
  
      osi_assertx(!(scp->flags & CM_SCACHEFLAG_INHASH), "CM_SCACHEFLAG_INHASH set");
  
- #if not_too_dangerous
-     /* dropping the cm_scacheLock allows more than one thread
-      * to obtain the same cm_scache_t from the LRU list.  Since
-      * the refCount is known to be zero at this point we have to
-      * assume that no one else is using the one this is returned.
-      */
-     lock_ReleaseWrite(&cm_scacheLock);
-     lock_ObtainWrite(&scp->rw);
-     lock_ObtainWrite(&cm_scacheLock);
- #endif
      scp->fid = *fidp;
      if (!cm_freelanceEnabled || !isRoot) {
          /* if this scache entry represents a volume root then we need 
--- 835,847 ----
  	    cm_PutVolume(volp);
  	return CM_ERROR_WOULDBLOCK;
      }
! #ifdef DEBUG_REFCOUNT
!     afsi_log("%s:%d cm_GetNewSCache returns scp 0x%p flags 0x%x", file, line, scp, scp->flags);
! #endif
!     osi_Log2(afsd_logp,"cm_GetNewSCache returns scp 0x%p flags 0x%x", scp, scp->flags);
  
      osi_assertx(!(scp->flags & CM_SCACHEFLAG_INHASH), "CM_SCACHEFLAG_INHASH set");
  
      scp->fid = *fidp;
      if (!cm_freelanceEnabled || !isRoot) {
          /* if this scache entry represents a volume root then we need 
***************
*** 864,874 ****
      scp->nextp = cm_data.scacheHashTablep[hash];
      cm_data.scacheHashTablep[hash] = scp;
      scp->flags |= CM_SCACHEFLAG_INHASH;
-     scp->refCount = 1;
-     osi_Log1(afsd_logp,"cm_GetSCache sets refCount to 1 scp 0x%x", scp);
- #if not_too_dangerous
      lock_ReleaseWrite(&scp->rw);
  #endif
  
      /* XXX - The following fields in the cm_scache are 
       * uninitialized:
--- 866,877 ----
      scp->nextp = cm_data.scacheHashTablep[hash];
      cm_data.scacheHashTablep[hash] = scp;
      scp->flags |= CM_SCACHEFLAG_INHASH;
      lock_ReleaseWrite(&scp->rw);
+     scp->refCount = 1;
+ #ifdef DEBUG_REFCOUNT
+     afsi_log("%s:%d cm_GetSCache sets refCount to 1 scp 0x%x", file, line, scp);
  #endif
+     osi_Log1(afsd_logp,"cm_GetSCache sets refCount to 1 scp 0x%x", scp);
  
      /* XXX - The following fields in the cm_scache are 
       * uninitialized:
***************
*** 876,889 ****
       *   parentVnode
       *   parentUnique
       */
-     lock_ReleaseWrite(&cm_scacheLock);
          
      /* now we have a held scache entry; just return it */
      *outScpp = scp;
  #ifdef DEBUG_REFCOUNT
!     afsi_log("%s:%d cm_GetSCache (4) outScpp 0x%p ref %d", file, line, scp, scp->refCount);
!     osi_Log1(afsd_logp,"cm_GetSCache (4) outScpp 0x%p", scp);
  #endif
      return 0;
  }
  
--- 879,892 ----
       *   parentVnode
       *   parentUnique
       */
          
      /* now we have a held scache entry; just return it */
      *outScpp = scp;
  #ifdef DEBUG_REFCOUNT
!     afsi_log("%s:%d cm_GetSCache (4) scp 0x%p ref %d", file, line, scp, scp->refCount);
!     osi_Log1(afsd_logp,"cm_GetSCache (4) scp 0x%p", scp);
  #endif
+     lock_ReleaseWrite(&cm_scacheLock);
      return 0;
  }
  
***************
*** 1044,1050 ****
      afs_uint32 sleep_buf_cmflags = 0;
      afs_uint32 sleep_scp_bufs = 0;
      int wakeupCycle;
-     int getAccessRights = 1;
  
      lock_AssertWrite(&scp->rw);
  
--- 1047,1052 ----
***************
*** 1249,1255 ****
              if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO))
                  return CM_ERROR_READONLY;
  
!             if (cm_HaveAccessRights(scp, userp, rights, &outRights) || !getAccessRights) {
                  if (~outRights & rights) 
  		    return CM_ERROR_NOACCESS;
              }
--- 1251,1257 ----
              if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO))
                  return CM_ERROR_READONLY;
  
!             if (cm_HaveAccessRights(scp, userp, rights, &outRights)) {
                  if (~outRights & rights) 
  		    return CM_ERROR_NOACCESS;
              }
***************
*** 1264,1270 ****
                  }
                  if (code) 
                      return code;
-                 getAccessRights = 0;    /* do not repeat */
                  continue;
              }
          }
--- 1266,1271 ----
***************
*** 1753,1759 ****
  	scp->cbServerp = NULL;
      }
      scp->cbExpires = 0;
!     scp->flags &= ~CM_SCACHEFLAG_CALLBACK;
      cm_dnlcPurgedp(scp);
      cm_dnlcPurgevp(scp);
      cm_FreeAllACLEnts(scp);
--- 1754,1760 ----
  	scp->cbServerp = NULL;
      }
      scp->cbExpires = 0;
!     scp->flags &= ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_LOCAL);
      cm_dnlcPurgedp(scp);
      cm_dnlcPurgevp(scp);
      cm_FreeAllACLEnts(scp);
***************
*** 1814,1825 ****
  #endif
  {
      afs_int32 refCount;
-     long      lockstate;
  
      osi_assertx(scp != NULL, "null cm_scache_t");
      lock_AssertAny(&cm_scacheLock);
  
-     lockstate = lock_GetRWLockState(&cm_scacheLock);
      refCount = InterlockedDecrement(&scp->refCount);
  #ifdef DEBUG_REFCOUNT
      if (refCount < 0)
--- 1815,1824 ----
***************
*** 1833,1848 ****
  
      if (refCount == 0 && (scp->flags & CM_SCACHEFLAG_DELETED)) {
          int deleted = 0;
          if (lockstate != OSI_RWLOCK_WRITEHELD) 
!             lock_ConvertRToW(&cm_scacheLock);
          lock_ObtainWrite(&scp->rw);
          if (scp->flags & CM_SCACHEFLAG_DELETED)
              deleted = 1;
!         lock_ReleaseWrite(&scp->rw);
!         if (refCount == 0 && deleted)
              cm_RecycleSCache(scp, 0);
!         if (lockstate != OSI_RWLOCK_WRITEHELD) 
!             lock_ConvertWToR(&cm_scacheLock);
      }
  }
  
--- 1832,1861 ----
  
      if (refCount == 0 && (scp->flags & CM_SCACHEFLAG_DELETED)) {
          int deleted = 0;
+         long      lockstate;
+ 
+         lockstate = lock_GetRWLockState(&cm_scacheLock);
          if (lockstate != OSI_RWLOCK_WRITEHELD) 
!             lock_ReleaseRead(&cm_scacheLock);
!         else
!             lock_ReleaseWrite(&cm_scacheLock);
! 
          lock_ObtainWrite(&scp->rw);
          if (scp->flags & CM_SCACHEFLAG_DELETED)
              deleted = 1;
! 
!         if (refCount == 0 && deleted) {
!             lock_ObtainWrite(&cm_scacheLock);
              cm_RecycleSCache(scp, 0);
!             if (lockstate != OSI_RWLOCK_WRITEHELD) 
!                 lock_ConvertWToR(&cm_scacheLock);
!         } else {
!             if (lockstate != OSI_RWLOCK_WRITEHELD) 
!                 lock_ObtainRead(&cm_scacheLock);
!             else
!                 lock_ObtainWrite(&cm_scacheLock);
!         }
!         lock_ReleaseWrite(&scp->rw);
      }
  }
  
***************
*** 1866,1886 ****
      osi_Log2(afsd_logp,"cm_ReleaseSCache scp 0x%p ref %d",scp, refCount);
      afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, refCount);
  #endif
  
      if (scp->flags & CM_SCACHEFLAG_DELETED) {
          int deleted = 0;
          lock_ObtainWrite(&scp->rw);
          if (scp->flags & CM_SCACHEFLAG_DELETED)
              deleted = 1;
-         lock_ReleaseWrite(&scp->rw);
          if (deleted) {
!             lock_ConvertRToW(&cm_scacheLock);
              cm_RecycleSCache(scp, 0);
!             lock_ConvertWToR(&cm_scacheLock);
          }
      }
- 
-     lock_ReleaseRead(&cm_scacheLock);
  }
  
  /* just look for the scp entry to get filetype */
--- 1879,1898 ----
      osi_Log2(afsd_logp,"cm_ReleaseSCache scp 0x%p ref %d",scp, refCount);
      afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, refCount);
  #endif
+     lock_ReleaseRead(&cm_scacheLock);
  
      if (scp->flags & CM_SCACHEFLAG_DELETED) {
          int deleted = 0;
          lock_ObtainWrite(&scp->rw);
          if (scp->flags & CM_SCACHEFLAG_DELETED)
              deleted = 1;
          if (deleted) {
!             lock_ObtainWrite(&cm_scacheLock);
              cm_RecycleSCache(scp, 0);
!             lock_ReleaseWrite(&cm_scacheLock);
          }
+         lock_ReleaseWrite(&scp->rw);
      }
  }
  
  /* just look for the scp entry to get filetype */
Index: openafs/src/WINNT/afsd/cm_scache.h
diff -c openafs/src/WINNT/afsd/cm_scache.h:1.21.2.27 openafs/src/WINNT/afsd/cm_scache.h:1.21.2.30
*** openafs/src/WINNT/afsd/cm_scache.h:1.21.2.27	Thu Jun 26 12:38:30 2008
--- openafs/src/WINNT/afsd/cm_scache.h	Tue Sep 16 07:47:47 2008
***************
*** 23,29 ****
  
  /* Key used for byte range locking.  Each unique key identifies a
     unique client per cm_scache_t for the purpose of locking. */
! typedef afs_uint64 cm_key_t;
  
  typedef struct cm_range {
      afs_int64 offset;
--- 23,33 ----
  
  /* Key used for byte range locking.  Each unique key identifies a
     unique client per cm_scache_t for the purpose of locking. */
! typedef struct cm_key {
!     afs_offs_t process_id;      /* process IDs can be 64bit on 64bit environments */
!     afs_uint16 session_id;
!     afs_uint16 file_id;
! } cm_key_t;
  
  typedef struct cm_range {
      afs_int64 offset;
***************
*** 257,262 ****
--- 261,267 ----
  
  #define CM_SCACHEFLAG_EACCESS           0x200000 /* Bulk Stat returned EACCES */
  #define CM_SCACHEFLAG_SMB_FID	        0x400000
+ #define CM_SCACHEFLAG_LOCAL             0x800000 /* Locally modified */
  
  /* sync flags for calls to the server.  The CM_SCACHEFLAG_FETCHING,
   * CM_SCACHEFLAG_STORING and CM_SCACHEFLAG_SIZESTORING flags correspond to the
***************
*** 409,412 ****
--- 414,419 ----
  extern void cm_AdjustScacheLRU(cm_scache_t *scp);
  
  extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
+ 
+ extern void cm_ResetSCacheDirectory(cm_scache_t *scp);
  #endif /*  __CM_SCACHE_H_ENV__ */
Index: openafs/src/WINNT/afsd/cm_server.c
diff -c openafs/src/WINNT/afsd/cm_server.c:1.25.2.31 openafs/src/WINNT/afsd/cm_server.c:1.25.2.37
*** openafs/src/WINNT/afsd/cm_server.c:1.25.2.31	Wed Aug 13 22:37:59 2008
--- openafs/src/WINNT/afsd/cm_server.c	Sat Sep 13 00:20:48 2008
***************
*** 19,24 ****
--- 19,25 ----
  
  #include "afsd.h"
  #include <WINNT\syscfg.h>
+ #include <WINNT/afsreg.h>
  #include <osi.h>
  #include <rx/rx.h>
  
***************
*** 37,43 ****
--- 38,46 ----
      lock_ObtainRead(&cm_serverLock);
      for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
          cm_GetServerNoLock(tsp);
+         lock_ReleaseRead(&cm_serverLock);
  	cm_ForceNewConnections(tsp);
+         lock_ObtainRead(&cm_serverLock);
          cm_PutServerNoLock(tsp);
      }
      lock_ReleaseRead(&cm_serverLock);
***************
*** 155,163 ****
              tsp->flags |= CM_SERVERFLAG_DOWN;
              tsp->downTime = time(NULL);
          }
! 	if (code != VRESTARTING)
  	    cm_ForceNewConnections(tsp);
! 
  	osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
  		  osi_LogSaveString(afsd_logp, hoststr), 
  		  tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
--- 158,168 ----
              tsp->flags |= CM_SERVERFLAG_DOWN;
              tsp->downTime = time(NULL);
          }
! 	if (code != VRESTARTING) {
!             lock_ReleaseMutex(&tsp->mx);
  	    cm_ForceNewConnections(tsp);
!             lock_ObtainMutex(&tsp->mx);
!         }
  	osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
  		  osi_LogSaveString(afsd_logp, hoststr), 
  		  tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
***************
*** 195,203 ****
      lock_ReleaseMutex(&tsp->mx);
  }
  
! #define MULTI_CHECKSERVERS 1
! #ifndef MULTI_CHECKSERVERS
! void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
  {
      /* ping all file servers, up or down, with unauthenticated connection,
       * to find out whether we have all our callbacks from the server still.
--- 200,206 ----
      lock_ReleaseMutex(&tsp->mx);
  }
  
! static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
  {
      /* ping all file servers, up or down, with unauthenticated connection,
       * to find out whether we have all our callbacks from the server still.
***************
*** 251,258 ****
      }
      lock_ReleaseRead(&cm_serverLock);
  }       
! #else /* MULTI_CHECKSERVERS */
! void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
  {
      /* 
       * The goal of this function is to probe simultaneously 
--- 254,261 ----
      }
      lock_ReleaseRead(&cm_serverLock);
  }       
! 
! static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
  {
      /* 
       * The goal of this function is to probe simultaneously 
***************
*** 272,278 ****
      cm_conn_t **conns = NULL;
      struct rx_connection **rxconns = NULL;
      cm_req_t req;
!     afs_int32 i, j, nconns = 0;
      afs_int32 *conntimer, *results;
      Capabilities *caps = NULL;
      cm_server_t ** serversp, *tsp;
--- 275,281 ----
      cm_conn_t **conns = NULL;
      struct rx_connection **rxconns = NULL;
      cm_req_t req;
!     afs_int32 i, j, nconns = 0, maxconns;
      afs_int32 *conntimer, *results;
      Capabilities *caps = NULL;
      cm_server_t ** serversp, *tsp;
***************
*** 284,307 ****
      char hoststr[16];
  
      cm_InitReq(&req);
  
!     j = max(cm_numFileServers,cm_numVldbServers);
!     conns = (cm_conn_t **)malloc(j * sizeof(cm_conn_t *));
!     rxconns = (struct rx_connection **)malloc(j * sizeof(struct rx_connection *));
!     conntimer = (afs_int32 *)malloc(j * sizeof (afs_int32));
!     deltas = (time_t *)malloc(j * sizeof (time_t));
!     results = (afs_int32 *)malloc(j * sizeof (afs_int32));
!     serversp = (cm_server_t **)malloc(j * sizeof(cm_server_t *));
!     caps = (Capabilities *)malloc(j * sizeof(Capabilities));
  
!     memset(caps, 0, j * sizeof(Capabilities));
  
      if ((flags & CM_FLAG_CHECKFILESERVERS) || 
          !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
      {
          lock_ObtainRead(&cm_serverLock);
!         nconns = 0;
!         for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
              if (tsp->type != CM_SERVER_FILE || 
                  tsp->cellp == NULL ||           /* SetPref only */
                  cellp && cellp != tsp->cellp)
--- 287,311 ----
      char hoststr[16];
  
      cm_InitReq(&req);
+     maxconns = max(cm_numFileServers,cm_numVldbServers);
+     if (maxconns == 0)
+         return;
  
!     conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
!     rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
!     conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
!     deltas = (time_t *)malloc(maxconns * sizeof (time_t));
!     results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
!     serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
!     caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
  
!     memset(caps, 0, maxconns * sizeof(Capabilities));
  
      if ((flags & CM_FLAG_CHECKFILESERVERS) || 
          !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
      {
          lock_ObtainRead(&cm_serverLock);
!         for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
              if (tsp->type != CM_SERVER_FILE || 
                  tsp->cellp == NULL ||           /* SetPref only */
                  cellp && cellp != tsp->cellp)
***************
*** 418,426 ****
                      tsp->flags |= CM_SERVERFLAG_DOWN;
                      tsp->downTime = time(NULL);
                  }
!                 if (code != VRESTARTING)
                      cm_ForceNewConnections(tsp);
! 
                  afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                  osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                            osi_LogSaveString(afsd_logp, hoststr), 
--- 422,432 ----
                      tsp->flags |= CM_SERVERFLAG_DOWN;
                      tsp->downTime = time(NULL);
                  }
!                 if (code != VRESTARTING) {
!                     lock_ReleaseMutex(&tsp->mx);
                      cm_ForceNewConnections(tsp);
!                     lock_ObtainMutex(&tsp->mx);
!                 }
                  afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                  osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                            osi_LogSaveString(afsd_logp, hoststr), 
***************
*** 547,555 ****
                      tsp->flags |= CM_SERVERFLAG_DOWN;
                      tsp->downTime = time(NULL);
                  }
!                 if (code != VRESTARTING)
                      cm_ForceNewConnections(tsp);
! 
                  afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                  osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                            osi_LogSaveString(afsd_logp, hoststr), 
--- 553,563 ----
                      tsp->flags |= CM_SERVERFLAG_DOWN;
                      tsp->downTime = time(NULL);
                  }
!                 if (code != VRESTARTING) {
!                     lock_ReleaseMutex(&tsp->mx);
                      cm_ForceNewConnections(tsp);
!                     lock_ObtainMutex(&tsp->mx);
!                 }
                  afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                  osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                            osi_LogSaveString(afsd_logp, hoststr), 
***************
*** 596,603 ****
          !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
      {
          lock_ObtainRead(&cm_serverLock);
!         nconns = 0;
!         for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
              if (tsp->type != CM_SERVER_VLDB ||
                  tsp->cellp == NULL ||           /* SetPref only */
                  cellp && cellp != tsp->cellp)
--- 604,610 ----
          !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
      {
          lock_ObtainRead(&cm_serverLock);
!         for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
              if (tsp->type != CM_SERVER_VLDB ||
                  tsp->cellp == NULL ||           /* SetPref only */
                  cellp && cellp != tsp->cellp)
***************
*** 648,654 ****
              } multi_End;
          }
  
!         /* Process results of servers that support RXAFS_GetCapabilities */
          for (i=0; i<nconns; i++) {
              if (conntimer[i])
                  rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
--- 655,661 ----
              } multi_End;
          }
  
!         /* Process results of servers that support VL_ProbeServer */
          for (i=0; i<nconns; i++) {
              if (conntimer[i])
                  rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
***************
*** 672,739 ****
                            osi_LogSaveString(afsd_logp, hoststr), 
                            tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
                            tsp->capabilities);
- 
-                 /* Now update the volume status if necessary */
-                 if (wasDown) {
-                     cm_server_vols_t * tsrvp;
-                     cm_volume_t * volp;
-                     int i;
- 
-                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
-                         for (i=0; i<NUM_SERVER_VOLS; i++) {
-                             if (tsrvp->ids[i] != 0) {
-                                 cm_InitReq(&req);
- 
-                                 lock_ReleaseMutex(&tsp->mx);
-                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
-                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
-                                 lock_ObtainMutex(&tsp->mx);
-                                 if (code == 0) {
-                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
-                                     cm_PutVolume(volp);
-                                 }
-                             }
-                         }
-                     }
-                 }
              } else {
                  /* mark server as down */
                  if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                      tsp->flags |= CM_SERVERFLAG_DOWN;
                      tsp->downTime = time(NULL);
                  }
!                 if (code != VRESTARTING)
                      cm_ForceNewConnections(tsp);
! 
                  afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                  osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                            osi_LogSaveString(afsd_logp, hoststr), 
                            tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
                            tsp->capabilities);
- 
-                 /* Now update the volume status if necessary */
-                 if (!wasDown) {
-                     cm_server_vols_t * tsrvp;
-                     cm_volume_t * volp;
-                     int i;
- 
-                     for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
-                         for (i=0; i<NUM_SERVER_VOLS; i++) {
-                             if (tsrvp->ids[i] != 0) {
-                                 cm_InitReq(&req);
- 
-                                 lock_ReleaseMutex(&tsp->mx);
-                                 code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
-                                                          &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
-                                 lock_ObtainMutex(&tsp->mx);
-                                 if (code == 0) {
-                                     cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
-                                     cm_PutVolume(volp);
-                                 }
-                             }
-                         }
-                     }
-                 }
              }
  
              if (tsp->waitCount == 0)
--- 679,700 ----
                            osi_LogSaveString(afsd_logp, hoststr), 
                            tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
                            tsp->capabilities);
              } else {
                  /* mark server as down */
                  if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                      tsp->flags |= CM_SERVERFLAG_DOWN;
                      tsp->downTime = time(NULL);
                  }
!                 if (code != VRESTARTING) {
!                     lock_ReleaseMutex(&tsp->mx);
                      cm_ForceNewConnections(tsp);
!                     lock_ObtainMutex(&tsp->mx);
!                 }
                  afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                  osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                            osi_LogSaveString(afsd_logp, hoststr), 
                            tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
                            tsp->capabilities);
              }
  
              if (tsp->waitCount == 0)
***************
*** 755,769 ****
      free(serversp);
      free(caps);
  }
! #endif /* MULTI_CHECKSERVERS */
  
  void cm_InitServer(void)
  {
      static osi_once_t once;
          
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_serverLock, "cm_serverLock");
!         lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock");
          osi_EndOnce(&once);
      }
  }
--- 716,751 ----
      free(serversp);
      free(caps);
  }
! 
! void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
! {
!     DWORD code;
!     HKEY parmKey;
!     DWORD dummyLen;
!     DWORD multi = 1;
! 
!     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
!                          0, KEY_QUERY_VALUE, &parmKey);
!     if (code == ERROR_SUCCESS) {
!         dummyLen = sizeof(multi);
!         code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
!                                 (BYTE *) &multi, &dummyLen);
!         RegCloseKey (parmKey);
!     }
! 
!     if (multi)
!         cm_CheckServersMulti(flags, cellp);
!     else
!         cm_CheckServersSingular(flags, cellp);
! }
  
  void cm_InitServer(void)
  {
      static osi_once_t once;
          
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
!         lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
          osi_EndOnce(&once);
      }
  }
***************
*** 905,911 ****
          tsp->type = type;
          tsp->cellp = cellp;
          tsp->refCount = 1;
!         lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
          tsp->addr = *socketp;
  
          cm_SetServerPrefs(tsp); 
--- 887,893 ----
          tsp->type = type;
          tsp->cellp = cellp;
          tsp->refCount = 1;
!         lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
          tsp->addr = *socketp;
  
          cm_SetServerPrefs(tsp); 
***************
*** 1052,1057 ****
--- 1034,1041 ----
  
      lock_ObtainRead(&cm_serverLock);
      for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+         if (tsrp->status == srv_deleted)
+             continue;
          if (first)
              first = 0;
          else
***************
*** 1252,1257 ****
--- 1236,1242 ----
      }
  }
  
+ /* Called with cm_serverLock write locked */
  void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
  {
      cm_server_vols_t * tsrvp;
***************
*** 1276,1281 ****
--- 1261,1269 ----
      cm_serverRef_t  **nextp = 0;
      cm_serverRef_t  * next = 0;
  
+ 	if (*list == NULL)
+ 		return;
+ 
      lock_ObtainWrite(&cm_serverLock);
  
      while (*current)
Index: openafs/src/WINNT/afsd/cm_user.c
diff -c openafs/src/WINNT/afsd/cm_user.c:1.8.4.6 openafs/src/WINNT/afsd/cm_user.c:1.8.4.7
*** openafs/src/WINNT/afsd/cm_user.c:1.8.4.6	Thu Jun 26 10:58:05 2008
--- openafs/src/WINNT/afsd/cm_user.c	Fri Aug 22 14:10:01 2008
***************
*** 29,35 ****
      static osi_once_t once;
          
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_userLock, "cm_userLock");
          osi_EndOnce(&once);
      }
          
--- 29,35 ----
      static osi_once_t once;
          
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_userLock, "cm_userLock", LOCK_HIERARCHY_USER_GLOBAL);
          osi_EndOnce(&once);
      }
          
***************
*** 43,49 ****
      userp = malloc(sizeof(*userp));
      memset(userp, 0, sizeof(*userp));
      userp->refCount = 1;
!     lock_InitializeMutex(&userp->mx, "cm_user_t");
      return userp;
  }
  
--- 43,49 ----
      userp = malloc(sizeof(*userp));
      memset(userp, 0, sizeof(*userp));
      userp->refCount = 1;
!     lock_InitializeMutex(&userp->mx, "cm_user_t", LOCK_HIERARCHY_USER);
      return userp;
  }
  
Index: openafs/src/WINNT/afsd/cm_utils.c
diff -c openafs/src/WINNT/afsd/cm_utils.c:1.11.4.13 openafs/src/WINNT/afsd/cm_utils.c:1.11.4.16
*** openafs/src/WINNT/afsd/cm_utils.c:1.11.4.13	Thu Jul 31 08:39:24 2008
--- openafs/src/WINNT/afsd/cm_utils.c	Tue Sep 16 07:34:31 2008
***************
*** 340,346 ****
  	cm_space_t *tsp;
  
  	if (osi_Once(&cm_utilsOnce)) {
! 		lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock");
  		osi_EndOnce(&cm_utilsOnce);
          }
          
--- 340,346 ----
  	cm_space_t *tsp;
  
  	if (osi_Once(&cm_utilsOnce)) {
! 		lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock", LOCK_HIERARCHY_UTILS_GLOBAL);
  		osi_EndOnce(&cm_utilsOnce);
          }
          
***************
*** 440,446 ****
  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
   'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
!  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
  };
  int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
  
--- 440,446 ----
  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
   'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
!  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
  };
  int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
  
***************
*** 657,662 ****
--- 657,670 ----
                                              cm_ClientCharNext(p), FALSE))
                      return TRUE;
              } /* endfor */
+             if (*pattern == '.' && *pattern_next == '\0') {
+                 for (p = name; p && *p; p = cm_ClientCharNext(p))
+                     if (*p == '.')
+                         break;
+                 if (p && *p)
+                     return FALSE;
+                 return TRUE;
+             }
              return FALSE;
  
          default:
***************
*** 681,688 ****
   */
  int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
  {
!     clientchar_t * newmask;
!     int    i, j, star, qmark, casefold, retval;
  
      /* make sure we only match 8.3 names, if requested */
      if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
--- 689,697 ----
   */
  int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
  {
!     clientchar_t *newmask, lastchar = _C('\0');
!     int    i, j, casefold, retval;
!     int  star = 0, qmark = 0, dot = 0;
  
      /* make sure we only match 8.3 names, if requested */
      if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
***************
*** 695,702 ****
       * for example  the sequence "*?*?*?*"
       * must be turned into the form "*"
       */
!     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+1)*sizeof(clientchar_t));
      for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
          switch ( maskp[i] ) {
          case '?':
          case '>':
--- 704,712 ----
       * for example  the sequence "*?*?*?*"
       * must be turned into the form "*"
       */
!     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
      for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
+         lastchar = maskp[i];
          switch ( maskp[i] ) {
          case '?':
          case '>':
***************
*** 706,711 ****
--- 716,724 ----
          case '*':
              star++;
              break;
+         case '.':
+             dot++;
+             /* fallthrough */
          default:
              if ( star ) {
                  newmask[j++] = '*';
***************
*** 724,729 ****
--- 737,744 ----
          while ( qmark-- )
              newmask[j++] = '?';
      }
+     if (dot == 0 && lastchar == '<')
+         newmask[j++] = '.';
      newmask[j++] = '\0';
  
      retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
Index: openafs/src/WINNT/afsd/cm_vnodeops.c
diff -c openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.88 openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.91
*** openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.88	Tue Aug 12 00:31:31 2008
--- openafs/src/WINNT/afsd/cm_vnodeops.c	Sat Sep 13 09:51:50 2008
***************
*** 254,260 ****
  	    (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
  	    if (!*ldpp) {
  		code = ENOMEM;
! 		goto _syncopdone;
  	    }
  
  	    (*ldpp)->key = key;
--- 254,260 ----
  	    (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
  	    if (!*ldpp) {
  		code = ENOMEM;
! 		goto _done;
  	    }
  
  	    (*ldpp)->key = key;
***************
*** 288,296 ****
          goto _done;
      }
  
-   _syncopdone:
-     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
- 
   _done:
      lock_ReleaseWrite(&scp->rw);
  
--- 288,293 ----
***************
*** 302,315 ****
  			       cm_lock_data_t ** ldpp)
  {
      osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
      if (*ldpp) {
- 	lock_ObtainWrite(&scp->rw);
  	cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength, 
  		  (*ldpp)->key, userp, reqp);
- 	lock_ReleaseWrite(&scp->rw);
  	free(*ldpp);
  	*ldpp = NULL;
      }
      return 0;
  }
  /*
--- 299,313 ----
  			       cm_lock_data_t ** ldpp)
  {
      osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
+     lock_ObtainWrite(&scp->rw);
      if (*ldpp) {
  	cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength, 
  		  (*ldpp)->key, userp, reqp);
  	free(*ldpp);
  	*ldpp = NULL;
      }
+     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+     lock_ReleaseWrite(&scp->rw);
      return 0;
  }
  /*
***************
*** 891,896 ****
--- 889,896 ----
      size_t vnLength;
      int targetType;
  
+     *outScpp = NULL;
+ 
      if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
          tfid = scp->mountRootFid;
          lock_ReleaseWrite(&scp->rw);
***************
*** 1013,1019 ****
  }       
  
  long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
!                        cm_req_t *reqp, cm_scache_t **outpScpp)
  {
      long code;
      int dnlcHit = 1;	/* did we hit in the dnlc? yes, we did */
--- 1013,1019 ----
  }       
  
  long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
!                        cm_req_t *reqp, cm_scache_t **outScpp)
  {
      long code;
      int dnlcHit = 1;	/* did we hit in the dnlc? yes, we did */
***************
*** 1024,1029 ****
--- 1024,1031 ----
      normchar_t *nnamep = NULL;
      fschar_t *fnamep = NULL;
  
+     *outScpp = NULL;
+ 
      memset(&rock, 0, sizeof(rock));
  
      if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
***************
*** 1222,1228 ****
      }
  
      /* copy back pointer */
!     *outpScpp = tscp;
  
      /* insert scache in dnlc */
      if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
--- 1224,1230 ----
      }
  
      /* copy back pointer */
!     *outScpp = tscp;
  
      /* insert scache in dnlc */
      if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
***************
*** 1281,1287 ****
  }   
  
  long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
!                                 cm_req_t *reqp, cm_scache_t ** outpScpp)
  {
      afs_uint32    code = 0;
      fschar_t      cellName[CELL_MAXNAMELEN];
--- 1283,1289 ----
  }   
  
  long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
!                                 cm_req_t *reqp, cm_scache_t ** outScpp)
  {
      afs_uint32    code = 0;
      fschar_t      cellName[CELL_MAXNAMELEN];
***************
*** 1370,1376 ****
  
      cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
  
!     code = cm_GetSCache(&fid, outpScpp, userp, reqp);
  
    _exit_cleanup:
      if (fnamep)
--- 1372,1378 ----
  
      cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
  
!     code = cm_GetSCache(&fid, outScpp, userp, reqp);
  
    _exit_cleanup:
      if (fnamep)
***************
*** 1391,1400 ****
  
  #ifdef DEBUG_REFCOUNT
  long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
!                cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
  #else
  long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
!                cm_req_t *reqp, cm_scache_t **outpScpp)
  #endif
  {
      long code;
--- 1393,1402 ----
  
  #ifdef DEBUG_REFCOUNT
  long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
!                cm_req_t *reqp, cm_scache_t **outScpp, char * file, long line)
  #else
  long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
!                cm_req_t *reqp, cm_scache_t **outScpp)
  #endif
  {
      long code;
***************
*** 1416,1422 ****
  
      if (dscp == cm_data.rootSCachep &&
          cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) == 0) {
!         return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outpScpp);
      }
  
      if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
--- 1418,1424 ----
  
      if (dscp == cm_data.rootSCachep &&
          cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) == 0) {
!         return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
      }
  
      if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
***************
*** 1430,1436 ****
  #endif
  
                  if (code == 0) {
!                     *outpScpp = scp;
                      return 0;
                  }
                  if (scp) {
--- 1432,1438 ----
  #endif
  
                  if (code == 0) {
!                     *outScpp = scp;
                      return 0;
                  }
                  if (scp) {
***************
*** 1443,1449 ****
                  afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
                  osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
  #endif
!                 *outpScpp = scp;
                  return code;
              }
          }
--- 1445,1451 ----
                  afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
                  osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
  #endif
!                 *outScpp = scp;
                  return code;
              }
          }
***************
*** 1453,1459 ****
          afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
          osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
  #endif
!         *outpScpp = scp;
          return code;
      }
  
--- 1455,1461 ----
          afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
          osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
  #endif
!         *outScpp = scp;
          return code;
      }
  
***************
*** 1804,1813 ****
      int fid_count = 0;          /* number of fids processed in this path walk */
      int i;
  
  #ifdef DEBUG_REFCOUNT
      afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
      osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %S tidpath %S flags 0x%x",
!              rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
               flags);
  #endif
  
--- 1806,1817 ----
      int fid_count = 0;          /* number of fids processed in this path walk */
      int i;
  
+     *outScpp = NULL;
+ 
  #ifdef DEBUG_REFCOUNT
      afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
      osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %S tidpath %S flags 0x%x",
!              rootSCachep, pathp ? pathp : L"<NULL>", tidPathp ? tidPathp : L"<NULL>", 
               flags);
  #endif
  
***************
*** 2073,2079 ****
          cm_ReleaseSCache(tscp);
  
  #ifdef DEBUG_REFCOUNT
!     afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp)->refCount);
  #endif
      osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
      return code;
--- 2077,2083 ----
          cm_ReleaseSCache(tscp);
  
  #ifdef DEBUG_REFCOUNT
!     afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp) ? (*outScpp)->refCount : 0);
  #endif
      osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
      return code;
***************
*** 2101,2106 ****
--- 2105,2112 ----
      cm_space_t *spacep;
      cm_scache_t *newRootScp;
  
+     *outScpp = NULL;
+ 
      osi_Log1(afsd_logp, "Evaluating symlink scp 0x%p", linkScp);
  
      code = cm_AssembleLink(linkScp, "", &newRootScp, &spacep, userp, reqp);
***************
*** 3902,3908 ****
  
          if (INTERSECT_RANGE(range, fileLock->range)) {
              if (IS_LOCK_ACTIVE(fileLock)) {
!                 if (fileLock->key == key) {
  
                      /* If there is an active lock for this client, it
                         is safe to substract ranges.*/
--- 3908,3914 ----
  
          if (INTERSECT_RANGE(range, fileLock->range)) {
              if (IS_LOCK_ACTIVE(fileLock)) {
!                 if (cm_KeyEquals(&fileLock->key, &key, 0)) {
  
                      /* If there is an active lock for this client, it
                         is safe to substract ranges.*/
***************
*** 3924,3930 ****
                          cm_LockRangeSubtract(&range, &fileLock->range);
                  }
              } else if (IS_LOCK_LOST(fileLock) &&
!                       (fileLock->key == key || fileLock->lockType == LockWrite)) {
                  code = CM_ERROR_BADFD;
                  break;
              }
--- 3930,3936 ----
                          cm_LockRangeSubtract(&range, &fileLock->range);
                  }
              } else if (IS_LOCK_LOST(fileLock) &&
!                        (cm_KeyEquals(&fileLock->key, &key, 0) || fileLock->lockType == LockWrite)) {
                  code = CM_ERROR_BADFD;
                  break;
              }
***************
*** 3983,3989 ****
  
          if (INTERSECT_RANGE(range, fileLock->range)) {
              if (IS_LOCK_ACTIVE(fileLock)) {
!                 if (fileLock->key == key) {
                      if (fileLock->lockType == LockWrite) {
  
                          /* if there is an active lock for this client, it
--- 3989,3995 ----
  
          if (INTERSECT_RANGE(range, fileLock->range)) {
              if (IS_LOCK_ACTIVE(fileLock)) {
!                 if (cm_KeyEquals(&fileLock->key, &key, 0)) {
                      if (fileLock->lockType == LockWrite) {
  
                          /* if there is an active lock for this client, it
***************
*** 4233,4240 ****
  
      osi_Log4(afsd_logp, "cm_Lock scp 0x%x type 0x%x offset %d length %d",
               scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
!     osi_Log3(afsd_logp, "... allowWait %d key 0x%x:%x", allowWait, 
!              (unsigned long)(key >> 32), (unsigned long)(key & 0xffffffff));
  
      /*
     A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
--- 4239,4246 ----
  
      osi_Log4(afsd_logp, "cm_Lock scp 0x%x type 0x%x offset %d length %d",
               scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
!     osi_Log4(afsd_logp, "... allowWait %d key <0x%x, 0x%x, 0x%x>", allowWait, 
!              key.process_id, key.session_id, key.file_id);
  
      /*
     A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
***************
*** 4268,4274 ****
              (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
  
          if (IS_LOCK_LOST(fileLock)) {
!             if (fileLock->key == key) {
                  code = CM_ERROR_BADFD;
                  break;
              } else if (fileLock->lockType == LockWrite && INTERSECT_RANGE(range, fileLock->range)) {
--- 4274,4280 ----
              (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
  
          if (IS_LOCK_LOST(fileLock)) {
!             if (cm_KeyEquals(&fileLock->key, &key, 0)) {
                  code = CM_ERROR_BADFD;
                  break;
              } else if (fileLock->lockType == LockWrite && INTERSECT_RANGE(range, fileLock->range)) {
***************
*** 4581,4588 ****
      return code;
  }
  
- static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags);
- 
  /* Called with scp->rw held */
  long cm_UnlockByKey(cm_scache_t * scp,
  		    cm_key_t key,
--- 4587,4592 ----
***************
*** 4595,4605 ****
      osi_queue_t *q, *qn;
      int n_unlocks = 0;
  
!     osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x flags=0x%x",
!              scp,
!              (unsigned long)(key >> 32),
!              (unsigned long)(key & 0xffffffff),
!              flags);
  
      lock_ObtainWrite(&cm_scacheLock);
  
--- 4599,4607 ----
      osi_queue_t *q, *qn;
      int n_unlocks = 0;
  
!     osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key <0x%x,0x%x,0x%x",
!              scp, key.process_id, key.session_id, key.file_id);
!     osi_Log1(afsd_logp, "    flags=0x%x", flags);
  
      lock_ObtainWrite(&cm_scacheLock);
  
***************
*** 4615,4623 ****
                   (unsigned long) fileLock->range.offset,
                   (unsigned long) fileLock->range.length,
                  fileLock->lockType);
!         osi_Log3(afsd_logp, "     key[0x%x:%x] flags[0x%x]",
!                  (unsigned long)(fileLock->key >> 32),
!                  (unsigned long)(fileLock->key & 0xffffffff),
                   fileLock->flags);
  
          if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
--- 4617,4624 ----
                   (unsigned long) fileLock->range.offset,
                   (unsigned long) fileLock->range.length,
                  fileLock->lockType);
!         osi_Log4(afsd_logp, "     key<0x%x, 0x%x, 0x%x> flags[0x%x]",
!                  fileLock->key.process_id, fileLock->key.session_id, fileLock->key.file_id,
                   fileLock->flags);
  
          if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
***************
*** 4637,4643 ****
  #endif
  
          if (!IS_LOCK_DELETED(fileLock) &&
!             cm_KeyEquals(fileLock->key, key, flags)) {
              osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
                      fileLock->range.offset,
                      fileLock->range.length,
--- 4638,4644 ----
  #endif
  
          if (!IS_LOCK_DELETED(fileLock) &&
!             cm_KeyEquals(&fileLock->key, &key, flags)) {
              osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
                      fileLock->range.offset,
                      fileLock->range.length,
***************
*** 4785,4792 ****
  
      osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
               scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
!     osi_Log2(afsd_logp, "... key 0x%x:%x",
!              (unsigned long) (key >> 32), (unsigned long) (key & 0xffffffff));
  
      lock_ObtainRead(&cm_scacheLock);
  
--- 4786,4793 ----
  
      osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
               scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
!     osi_Log3(afsd_logp, "... key <0x%x,0x%x,0x%x>",
!              key.process_id, key.session_id, key.file_id);
  
      lock_ObtainRead(&cm_scacheLock);
  
***************
*** 4811,4817 ****
          }
  #endif
          if (!IS_LOCK_DELETED(fileLock) &&
!             fileLock->key == key &&
              fileLock->range.offset == LOffset.QuadPart &&
              fileLock->range.length == LLength.QuadPart) {
              break;
--- 4812,4818 ----
          }
  #endif
          if (!IS_LOCK_DELETED(fileLock) &&
!             cm_KeyEquals(&fileLock->key, &key, 0) &&
              fileLock->range.offset == LOffset.QuadPart &&
              fileLock->range.length == LLength.QuadPart) {
              break;
***************
*** 5233,5241 ****
               (unsigned)(oldFileLock->range.offset & 0xffffffff),
               (unsigned)(oldFileLock->range.length >> 32),
               (unsigned)(oldFileLock->range.length & 0xffffffff));
!     osi_Log3(afsd_logp, "    key(%x:%x) flags=%x",
!              (unsigned)(oldFileLock->key >> 32),
!              (unsigned)(oldFileLock->key & 0xffffffff),
               (unsigned)(oldFileLock->flags));
  
      /* if the lock has already been granted, then we have nothing to do */
--- 5234,5241 ----
               (unsigned)(oldFileLock->range.offset & 0xffffffff),
               (unsigned)(oldFileLock->range.length >> 32),
               (unsigned)(oldFileLock->range.length & 0xffffffff));
!     osi_Log4(afsd_logp, "    key<0x%x,0x%x,0x%x> flags=%x",
!              oldFileLock->key.process_id, oldFileLock->key.session_id, oldFileLock->key.file_id,
               (unsigned)(oldFileLock->flags));
  
      /* if the lock has already been granted, then we have nothing to do */
***************
*** 5307,5313 ****
                  ((char *) q - offsetof(cm_file_lock_t, fileq));
  
              if (IS_LOCK_LOST(fileLock)) {
!                 if (fileLock->key == oldFileLock->key) {
                      code = CM_ERROR_BADFD;
                      oldFileLock->flags |= CM_FILELOCK_FLAG_LOST;
                      osi_Log1(afsd_logp, "    found lost lock %p for same key.  Marking lock as lost",
--- 5307,5313 ----
                  ((char *) q - offsetof(cm_file_lock_t, fileq));
  
              if (IS_LOCK_LOST(fileLock)) {
!                 if (cm_KeyEquals(&fileLock->key, &oldFileLock->key, 0)) {
                      code = CM_ERROR_BADFD;
                      oldFileLock->flags |= CM_FILELOCK_FLAG_LOST;
                      osi_Log1(afsd_logp, "    found lost lock %p for same key.  Marking lock as lost",
***************
*** 5509,5535 ****
      return code;
  }
  
! cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int file_id)
  {
! #ifdef DEBUG
!     osi_assertx((process_id & 0xffffffff) == process_id, "unexpected process_id");
!     osi_assertx((session_id & 0xffff) == session_id, "unexpected session_id");
!     osi_assertx((file_id & 0xffff) == file_id, "unexpected file_id");
! #endif
  
!     return 
!         (((cm_key_t) (process_id & 0xffffffff)) << 32) |
!         (((cm_key_t) (session_id & 0xffff)) << 16) |
!         (((cm_key_t) (file_id & 0xffff)));
  }
  
! static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags)
  {
!     if (flags & CM_UNLOCK_BY_FID) {
!         return ((k1 & 0xffffffff) == (k2 & 0xffffffff));
!     } else {
!         return (k1 == k2);
!     }
  }
  
  void cm_ReleaseAllLocks(void)
--- 5509,5529 ----
      return code;
  }
  
! cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
  {
!     cm_key_t key;
! 
!     key.process_id = process_id;
!     key.session_id = session_id;
!     key.file_id = file_id;
  
!     return key;
  }
  
! int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
  {
!     return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
!         ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
  }
  
  void cm_ReleaseAllLocks(void)
Index: openafs/src/WINNT/afsd/cm_vnodeops.h
diff -c openafs/src/WINNT/afsd/cm_vnodeops.h:1.14.4.13 openafs/src/WINNT/afsd/cm_vnodeops.h:1.14.4.14
*** openafs/src/WINNT/afsd/cm_vnodeops.h:1.14.4.13	Thu Jul 24 13:56:54 2008
--- openafs/src/WINNT/afsd/cm_vnodeops.h	Sat Sep 13 09:51:50 2008
***************
*** 231,237 ****
  #define CM_SESSION_CMINT    0xfffd
  #define CM_SESSION_RESERVED 0xfff0
  
! extern cm_key_t cm_GenerateKey(unsigned int session, unsigned long process_id, unsigned int file_id);
  
  #define MAX_SYMLINK_COUNT 16
  
--- 231,239 ----
  #define CM_SESSION_CMINT    0xfffd
  #define CM_SESSION_RESERVED 0xfff0
  
! extern cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id);
! 
! extern int cm_KeyEquals(cm_key_t * k1, cm_key_t * k2, int flags);
  
  #define MAX_SYMLINK_COUNT 16
  
Index: openafs/src/WINNT/afsd/cm_volume.c
diff -c openafs/src/WINNT/afsd/cm_volume.c:1.14.4.50 openafs/src/WINNT/afsd/cm_volume.c:1.14.4.55
*** openafs/src/WINNT/afsd/cm_volume.c:1.14.4.50	Thu Aug 14 16:21:27 2008
--- openafs/src/WINNT/afsd/cm_volume.c	Wed Sep 24 18:42:55 2008
***************
*** 83,89 ****
      static osi_once_t once;
  
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock");
  
          if ( newFile ) {
              cm_data.allVolumesp = NULL;
--- 83,89 ----
      static osi_once_t once;
  
      if (osi_Once(&once)) {
!         lock_InitializeRWLock(&cm_volumeLock, "cm global volume lock", LOCK_HIERARCHY_VOLUME_GLOBAL);
  
          if ( newFile ) {
              cm_data.allVolumesp = NULL;
***************
*** 100,113 ****
              for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
                  afs_uint32 volType;
  
!                 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock");
                  volp->flags |= CM_VOLUMEFLAG_RESET;
                  volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
                  for (volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
                      volp->vol[volType].state = vl_unknown;
                      volp->vol[volType].serversp = NULL;
                      if (volp->vol[volType].ID)
!                         cm_VolumeStatusNotification(volp, volp->vol[volType].ID, vl_alldown, volp->vol[volType].state);
                  }
                  volp->cbExpiresRO = 0;
              }
--- 100,113 ----
              for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
                  afs_uint32 volType;
  
!                 lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
                  volp->flags |= CM_VOLUMEFLAG_RESET;
                  volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
                  for (volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
                      volp->vol[volType].state = vl_unknown;
                      volp->vol[volType].serversp = NULL;
                      if (volp->vol[volType].ID)
!                         cm_VolumeStatusNotification(volp, volp->vol[volType].ID, vl_unknown, volp->vol[volType].state);
                  }
                  volp->cbExpiresRO = 0;
              }
***************
*** 227,233 ****
              cm_UpdateCell(cellp, 0);
  
          /* now we have volume structure locked and held; make RPC to fill it */
! 	osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", volp->cellp->name, volp->namep);
          do {
              struct rx_connection * rxconnp;
  
--- 227,235 ----
              cm_UpdateCell(cellp, 0);
  
          /* now we have volume structure locked and held; make RPC to fill it */
! 	osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", 
!                   osi_LogSaveString(afsd_logp,volp->cellp->name), 
!                   osi_LogSaveString(afsd_logp,volp->namep));
          do {
              struct rx_connection * rxconnp;
  
***************
*** 254,263 ****
          code = cm_MapVLRPCError(code, reqp);
  	if ( code )
  	    osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x", 
! 		      volp->cellp->name, volp->namep, code);
  	else
  	    osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS", 
! 		      volp->cellp->name, volp->namep);
      }
  
      /* We can end up here with code == CM_ERROR_NOSUCHVOLUME if the base volume name
--- 256,267 ----
          code = cm_MapVLRPCError(code, reqp);
  	if ( code )
  	    osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x", 
! 		      osi_LogSaveString(afsd_logp,volp->cellp->name), 
!                       osi_LogSaveString(afsd_logp,volp->namep), code);
  	else
  	    osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS", 
! 		      osi_LogSaveString(afsd_logp,volp->cellp->name), 
!                       osi_LogSaveString(afsd_logp,volp->namep));
      }
  
      /* We can end up here with code == CM_ERROR_NOSUCHVOLUME if the base volume name
***************
*** 271,277 ****
          snprintf(name, VL_MAXNAMELEN, "%s.readonly", volp->namep);
                  
          /* now we have volume structure locked and held; make RPC to fill it */
! 	osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", volp->cellp->name, 
                   osi_LogSaveString(afsd_logp,name));
          do {
              struct rx_connection * rxconnp;
--- 275,282 ----
          snprintf(name, VL_MAXNAMELEN, "%s.readonly", volp->namep);
                  
          /* now we have volume structure locked and held; make RPC to fill it */
! 	osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s", 
!                  osi_LogSaveString(afsd_logp,volp->cellp->name),
                   osi_LogSaveString(afsd_logp,name));
          do {
              struct rx_connection * rxconnp;
***************
*** 299,308 ****
          code = cm_MapVLRPCError(code, reqp);
  	if ( code )
  	    osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x", 
! 		      volp->cellp->name, osi_LogSaveString(afsd_logp,name), code);
  	else
  	    osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS", 
! 		      volp->cellp->name, osi_LogSaveString(afsd_logp,name));
      }
      
      lock_ObtainWrite(&volp->rw);
--- 304,315 ----
          code = cm_MapVLRPCError(code, reqp);
  	if ( code )
  	    osi_Log3(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s FAILURE, code 0x%x", 
! 		     osi_LogSaveString(afsd_logp,volp->cellp->name), 
!                      osi_LogSaveString(afsd_logp,name), code);
  	else
  	    osi_Log2(afsd_logp, "CALL VL_GetEntryByName{UNO} name %s:%s SUCCESS", 
! 		     osi_LogSaveString(afsd_logp,volp->cellp->name), 
!                      osi_LogSaveString(afsd_logp,name));
      }
      
      lock_ObtainWrite(&volp->rw);
***************
*** 427,433 ****
                  name[len - 9] = '\0';
              }
              
!             osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s", volp->namep, name);
  
              if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
                  cm_RemoveVolumeFromNameHashTable(volp);
--- 434,441 ----
                  name[len - 9] = '\0';
              }
              
!             osi_Log2(afsd_logp, "cm_UpdateVolume name %s -> %s", 
!                      osi_LogSaveString(afsd_logp,volp->namep), osi_LogSaveString(afsd_logp,name));
  
              if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
                  cm_RemoveVolumeFromNameHashTable(volp);
***************
*** 558,563 ****
--- 566,572 ----
              cm_RandomizeServer(&volp->vol[ROVOL].serversp);
          }
  
+ 
          rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
          roNewstate = roServers_alldown ? vl_alldown : vl_online;
          bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
***************
*** 604,610 ****
  
      volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
      osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x", 
!              volp->cellp->name, volp->namep, volp->flags, code);
      osi_Wakeup((LONG_PTR) &volp->flags);
  
      return code;
--- 613,620 ----
  
      volp->flags &= ~CM_VOLUMEFLAG_UPDATING_VL;
      osi_Log4(afsd_logp, "cm_UpdateVolumeLocation done, waking others name %s:%s flags 0x%x code 0x%x", 
!              osi_LogSaveString(afsd_logp,volp->cellp->name), 
!              osi_LogSaveString(afsd_logp,volp->namep), volp->flags, code);
      osi_Wakeup((LONG_PTR) &volp->flags);
  
      return code;
***************
*** 846,851 ****
--- 856,864 ----
                      cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_unknown);
                  volp->vol[volType].ID = 0;
                  cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
+                 lock_ReleaseWrite(&cm_volumeLock);
+                 cm_FreeServerList(&volp->vol[volType].serversp, CM_FREESERVERLIST_DELETE);
+                 lock_ObtainWrite(&cm_volumeLock);
              }
  	} else {
  	    volp = &cm_data.volumeBaseAddress[cm_data.currentVolumes++];
***************
*** 853,859 ****
  	    volp->magic = CM_VOLUME_MAGIC;
  	    volp->allNextp = cm_data.allVolumesp;
  	    cm_data.allVolumesp = volp;
! 	    lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock");
              lock_ReleaseWrite(&cm_volumeLock);
              lock_ObtainWrite(&volp->rw);
              lock_ObtainWrite(&cm_volumeLock);
--- 866,872 ----
  	    volp->magic = CM_VOLUME_MAGIC;
  	    volp->allNextp = cm_data.allVolumesp;
  	    cm_data.allVolumesp = volp;
! 	    lock_InitializeRWLock(&volp->rw, "cm_volume_t rwlock", LOCK_HIERARCHY_VOLUME);
              lock_ReleaseWrite(&cm_volumeLock);
              lock_ObtainWrite(&volp->rw);
              lock_ObtainWrite(&cm_volumeLock);
***************
*** 910,916 ****
      return code;
  }	
  
! void cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_cell_t *cellp;
      cm_volume_t *volp;
--- 923,934 ----
      return code;
  }	
  
! /* 
!  * Only call this function in response to a VNOVOL or VMOVED error
!  * from a file server.  Do not call it in response to CM_ERROR_NOSUCHVOLUME
!  * as that can lead to recursive calls.
!  */
! long cm_ForceUpdateVolume(cm_fid_t *fidp, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_cell_t *cellp;
      cm_volume_t *volp;
***************
*** 918,928 ****
      cm_volume_t *volp2;
  #endif
      afs_uint32  hash;
  
!     if (!fidp) return;
  
      cellp = cm_FindCellByID(fidp->cell, 0);
!     if (!cellp) return;
  
      /* search for the volume */
      lock_ObtainRead(&cm_volumeLock);
--- 936,949 ----
      cm_volume_t *volp2;
  #endif
      afs_uint32  hash;
+     long code;
  
!     if (!fidp) 
!         return CM_ERROR_INVAL;
  
      cellp = cm_FindCellByID(fidp->cell, 0);
!     if (!cellp) 
!         return CM_ERROR_NOSUCHCELL;
  
      /* search for the volume */
      lock_ObtainRead(&cm_volumeLock);
***************
*** 970,1007 ****
      lock_ReleaseRead(&cm_volumeLock);
  
      if (!volp)
!         return;
  
      /* update it */
      cm_data.mountRootGen = time(NULL);
      lock_ObtainWrite(&volp->rw);
      volp->flags |= CM_VOLUMEFLAG_RESET;
! #ifdef COMMENT
!     /* Mark the volume to be updated but don't update it now.
!      * This function is called only from within cm_Analyze
!      * when cm_ConnByMServers has failed with all servers down
!      * The problem is that cm_UpdateVolume is going to call
!      * cm_ConnByMServers which may cause a recursive chain
!      * of calls each returning a retry on failure.
!      * Instead, set the flag so the next time the volume is
!      * accessed by Name or ID the UpdateVolume call will
!      * occur.
!      */
      code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
- #endif
      lock_ReleaseWrite(&volp->rw);
  
      lock_ObtainRead(&cm_volumeLock);
      cm_PutVolume(volp);
      lock_ReleaseRead(&cm_volumeLock);
  }
  
  /* find the appropriate servers from a volume */
! cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume)
  {
      cm_serverRef_t **serverspp;
!     cm_serverRef_t *current;;
  
      lock_ObtainWrite(&cm_serverLock);
  
      if (volume == volp->vol[RWVOL].ID)
--- 991,1021 ----
      lock_ReleaseRead(&cm_volumeLock);
  
      if (!volp)
!         return CM_ERROR_NOSUCHVOLUME;
  
      /* update it */
      cm_data.mountRootGen = time(NULL);
      lock_ObtainWrite(&volp->rw);
      volp->flags |= CM_VOLUMEFLAG_RESET;
! 
      code = cm_UpdateVolumeLocation(cellp, userp, reqp, volp);
      lock_ReleaseWrite(&volp->rw);
  
      lock_ObtainRead(&cm_volumeLock);
      cm_PutVolume(volp);
      lock_ReleaseRead(&cm_volumeLock);
+ 
+     return code;
  }
  
  /* find the appropriate servers from a volume */
! cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume, cm_user_t *userp, cm_req_t *reqp)
  {
      cm_serverRef_t **serverspp;
!     cm_serverRef_t *current;
!     int firstTry = 1;
  
+   start:
      lock_ObtainWrite(&cm_serverLock);
  
      if (volume == volp->vol[RWVOL].ID)
***************
*** 1010,1019 ****
          serverspp = &volp->vol[ROVOL].serversp;
      else if (volume == volp->vol[BACKVOL].ID)
          serverspp = &volp->vol[BACKVOL].serversp;
!     else 
!         osi_panic("bad volume ID in cm_GetVolServers", __FILE__, __LINE__);
!         
!     for (current = *serverspp; current; current = current->next)
          current->refCount++;
  
      lock_ReleaseWrite(&cm_serverLock);
--- 1024,1049 ----
          serverspp = &volp->vol[ROVOL].serversp;
      else if (volume == volp->vol[BACKVOL].ID)
          serverspp = &volp->vol[BACKVOL].serversp;
!     else {
!         lock_ReleaseWrite(&cm_serverLock);
!         if (firstTry) {
!             afs_int32 code;
!             firstTry = 0;
!             lock_ObtainWrite(&volp->rw);
!             volp->flags |= CM_VOLUMEFLAG_RESET;
!             code = cm_UpdateVolumeLocation(volp->cellp, userp, reqp, volp);
!             lock_ReleaseWrite(&volp->rw);
!             if (code == 0)
!                 goto start;
!         }
!         return NULL;
!     }
! 
!     /* 
!      * Increment the refCount on deleted items as well.
!      * They will be freed by cm_FreeServerList when they get to zero 
!      */
!     for (current = *serverspp; current; current = current->next) 
          current->refCount++;
  
      lock_ReleaseWrite(&cm_serverLock);
***************
*** 1088,1099 ****
  
  }
  
! 
! /* The return code is 0 if the volume is not online and 
!  * 1 if the volume is online
!  */
! long
! cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
  {
      cm_conn_t *connp;
      long code;
--- 1118,1126 ----
  
  }
  
! void
! cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, afs_uint32 volID,
!                            afs_uint32 *onlinep, afs_uint32 *volumeUpdatedp)
  {
      cm_conn_t *connp;
      long code;
***************
*** 1106,1245 ****
      char volName[32];
      char offLineMsg[256];
      char motd[256];
!     long online = 0;
      cm_serverRef_t *serversp;
  
      Name = volName;
      OfflineMsg = offLineMsg;
      MOTD = motd;
  
!     lock_ObtainWrite(&volp->rw);
! 
!     if (volp->flags & CM_VOLUMEFLAG_RESET) {
!         cm_InitReq(&req);
!         code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
!     }
! 
!     if (volp->vol[RWVOL].ID != 0 && (!volID || volID == volp->vol[RWVOL].ID) &&
!          volp->vol[RWVOL].serversp) {
!        
!         for (serversp = volp->vol[RWVOL].serversp; serversp; serversp = serversp->next) {
!             if (serversp->status == srv_busy || serversp->status == srv_offline) {
!                 serversp->status = srv_not_busy;
!                 online = 1;
!             }
!         }
! 
!         if (volp->vol[RWVOL].state == vl_busy || volp->vol[RWVOL].state == vl_offline || volp->vol[RWVOL].state == vl_unknown) {
              cm_InitReq(&req);
  
!             lock_ReleaseWrite(&volp->rw);
!             do {
!                 code = cm_ConnFromVolume(volp, volp->vol[RWVOL].ID, cm_rootUserp, &req, &connp);
!                 if (code) 
                      continue;
  
!                 rxconnp = cm_GetRxConn(connp);
!                 code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[RWVOL].ID,
!                                              &volStat, &Name, &OfflineMsg, &MOTD);
!                 rx_PutConnection(rxconnp);            
! 
!             } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
!             code = cm_MapRPCError(code, &req);
! 
!             lock_ObtainWrite(&volp->rw);
!             if (code == 0 && volStat.Online) {
!                 cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, vl_online);
!                 volp->vol[RWVOL].state = vl_online;
!                 online = 1;
!             } else if (code == CM_ERROR_NOACCESS) {
!                 cm_VolumeStatusNotification(volp, volp->vol[RWVOL].ID, volp->vol[RWVOL].state, vl_unknown);
!                 volp->vol[RWVOL].state = vl_unknown;
!                 online = 1;
              }
-         }
-     }
- 
-     if (volp->vol[ROVOL].ID != 0 && (!volID || volID == volp->vol[ROVOL].ID) &&
-          volp->vol[ROVOL].serversp) {
  
!         for (serversp = volp->vol[ROVOL].serversp; serversp; serversp = serversp->next) {
!             if (serversp->status == srv_busy || serversp->status == srv_offline) {
!                 serversp->status = srv_not_busy;
!                 online = 1;
              }
-         }
  
!         if (volp->vol[ROVOL].state == vl_busy || volp->vol[ROVOL].state == vl_offline || volp->vol[ROVOL].state == vl_unknown) {
!             cm_InitReq(&req);
  
!             lock_ReleaseWrite(&volp->rw);
!             do {
!                 code = cm_ConnFromVolume(volp, volp->vol[ROVOL].ID, cm_rootUserp, &req, &connp);
!                 if (code) 
!                     continue;
  
!                 rxconnp = cm_GetRxConn(connp);
!                 code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[ROVOL].ID,
!                                               &volStat, &Name, &OfflineMsg, &MOTD);
!                 rx_PutConnection(rxconnp);        
  
!             } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
!             code = cm_MapRPCError(code, &req);
  
!             lock_ObtainWrite(&volp->rw);
!             if (code == 0 && volStat.Online) {
!                 cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, vl_online);
!                 volp->vol[ROVOL].state = vl_online;
!                 online = 1;
!             } else if (code == CM_ERROR_NOACCESS) {
!                 cm_VolumeStatusNotification(volp, volp->vol[ROVOL].ID, volp->vol[ROVOL].state, vl_unknown);
!                 volp->vol[ROVOL].state = vl_unknown;
!                 online = 1;
!             }
          }
      }
  
!     if (volp->vol[BACKVOL].ID != 0 && (!volID || volID == volp->vol[BACKVOL].ID) &&
!          volp->vol[BACKVOL].serversp) {
!         
!         for (serversp = volp->vol[BACKVOL].serversp; serversp; serversp = serversp->next) {
!             if (serversp->status == srv_busy || serversp->status == srv_offline) {
!                 serversp->status = srv_not_busy;
!                 online = 1;
!             }
!         }
! 
!         if (volp->vol[BACKVOL].state == vl_busy || volp->vol[BACKVOL].state == vl_offline || volp->vol[BACKVOL].state == vl_unknown) {
!             cm_InitReq(&req);
! 
!             lock_ReleaseWrite(&volp->rw);
!             do {
!                 code = cm_ConnFromVolume(volp, volp->vol[BACKVOL].ID, cm_rootUserp, &req, &connp);
!                 if (code) 
!                     continue;
! 
!                 rxconnp = cm_GetRxConn(connp);
!                 code = RXAFS_GetVolumeStatus(rxconnp, volp->vol[BACKVOL].ID,
!                                               &volStat, &Name, &OfflineMsg, &MOTD);
!                 rx_PutConnection(rxconnp);        
  
!             } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
!             code = cm_MapRPCError(code, &req);
  
!             lock_ObtainWrite(&volp->rw);
!             if (code == 0 && volStat.Online) {
!                 cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, vl_online);
!                 volp->vol[BACKVOL].state = vl_online;
!                 online = 1;
!             } else if (code == CM_ERROR_NOACCESS) {
!                 cm_VolumeStatusNotification(volp, volp->vol[BACKVOL].ID, volp->vol[BACKVOL].state, vl_unknown);
!                 volp->vol[BACKVOL].state = vl_unknown;
!                 online = 1;
!             }
!         }
      }
  
      lock_ReleaseWrite(&volp->rw);
      return online;
  }
--- 1133,1235 ----
      char volName[32];
      char offLineMsg[256];
      char motd[256];
!     long alldown, alldeleted;
      cm_serverRef_t *serversp;
  
      Name = volName;
      OfflineMsg = offLineMsg;
      MOTD = motd;
  
!     if (statep->ID != 0 && (!volID || volID == statep->ID)) {
!         if (!statep->serversp && !(*volumeUpdatedp)) {
              cm_InitReq(&req);
+             code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
+             *volumeUpdatedp = 1;
+         }
  
!         if (statep->serversp) {
!             alldown = 1;
!             alldeleted = 1;
!             for (serversp = statep->serversp; serversp; serversp = serversp->next) {
!                 if (serversp->status == srv_deleted)
                      continue;
  
!                 alldeleted = 0;
!                 *onlinep = 1;
!                 alldown = 0;
!                 
!                 if (serversp->status == srv_busy || serversp->status == srv_offline)
!                     serversp->status = srv_not_busy;
              }
  
!             if (alldeleted && !(*volumeUpdatedp)) {
!                 cm_InitReq(&req);
!                 code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
!                 *volumeUpdatedp = 1;
              }
  
!             if (statep->state == vl_busy || statep->state == vl_offline || statep->state == vl_unknown ||
!                 (!alldown && statep->state == vl_alldown)) {
!                 cm_InitReq(&req);
  
!                 lock_ReleaseWrite(&volp->rw);
!                 do {
!                     code = cm_ConnFromVolume(volp, statep->ID, cm_rootUserp, &req, &connp);
!                     if (code) 
!                         continue;
  
!                     rxconnp = cm_GetRxConn(connp);
!                     code = RXAFS_GetVolumeStatus(rxconnp, statep->ID,
!                                                  &volStat, &Name, &OfflineMsg, &MOTD);
!                     rx_PutConnection(rxconnp);            
  
!                 } while (cm_Analyze(connp, cm_rootUserp, &req, NULL, NULL, NULL, NULL, code));
!                 code = cm_MapRPCError(code, &req);
  
!                 lock_ObtainWrite(&volp->rw);
!                 if (code == 0 && volStat.Online) {
!                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
!                     statep->state = vl_online;
!                     *onlinep = 1;
!                 } else if (code == CM_ERROR_NOACCESS) {
!                     cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_unknown);
!                     statep->state = vl_unknown;
!                     *onlinep = 1;
!                 }
!             } else if (alldown && statep->state != vl_alldown) {
!                 cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
!                 statep->state = vl_alldown;
!             }
!         } else if (statep->state != vl_alldown) {
!             cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_alldown);
!             statep->state = vl_alldown;
          }
      }
+ }
  
! /* The return code is 0 if the volume is not online and 
!  * 1 if the volume is online
!  */
! long
! cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID)
! {
!     long code;
!     cm_req_t req;
!     afs_uint32 online = 0;
!     afs_uint32 volumeUpdated = 0;
  
!     lock_ObtainWrite(&volp->rw);
  
!     if (volp->flags & CM_VOLUMEFLAG_RESET) {
!         cm_InitReq(&req);
!         code = cm_UpdateVolumeLocation(volp->cellp, cm_rootUserp, &req, volp);
!         volumeUpdated = 1;
      }
  
+     cm_CheckOfflineVolumeState(volp, &volp->vol[RWVOL], volID, &online, &volumeUpdated);
+     cm_CheckOfflineVolumeState(volp, &volp->vol[ROVOL], volID, &online, &volumeUpdated);
+     cm_CheckOfflineVolumeState(volp, &volp->vol[BACKVOL], volID, &online, &volumeUpdated);
+ 
      lock_ReleaseWrite(&volp->rw);
      return online;
  }
***************
*** 1283,1288 ****
--- 1273,1280 ----
  
      lock_ObtainWrite(&cm_serverLock);
      for (tsrp = statep->serversp; tsrp; tsrp=tsrp->next) {
+         if (tsrp->status == srv_deleted)
+             continue;
          tsp = tsrp->server;
          if (tsp) {
              cm_GetServerNoLock(tsp);
Index: openafs/src/WINNT/afsd/cm_volume.h
diff -c openafs/src/WINNT/afsd/cm_volume.h:1.5.6.14 openafs/src/WINNT/afsd/cm_volume.h:1.5.6.16
*** openafs/src/WINNT/afsd/cm_volume.h:1.5.6.14	Wed May 28 13:34:52 2008
--- openafs/src/WINNT/afsd/cm_volume.h	Wed Sep 24 18:42:55 2008
***************
*** 89,98 ****
  
  extern long cm_GetROVolumeID(cm_volume_t *volp);
  
! extern void cm_ForceUpdateVolume(struct cm_fid *fidp, cm_user_t *userp,
  	cm_req_t *reqp);
  
! extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume);
  
  extern void cm_ChangeRankVolume(cm_server_t *tsp);
  
--- 89,99 ----
  
  extern long cm_GetROVolumeID(cm_volume_t *volp);
  
! extern long cm_ForceUpdateVolume(struct cm_fid *fidp, cm_user_t *userp,
  	cm_req_t *reqp);
  
! extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume, 
!                                          cm_user_t *userp, cm_req_t *reqp);
  
  extern void cm_ChangeRankVolume(cm_server_t *tsp);
  
***************
*** 124,129 ****
--- 125,134 ----
  
  extern long cm_CheckOfflineVolume(cm_volume_t *volp, afs_uint32 volID);
  
+ extern void cm_CheckOfflineVolumeState(cm_volume_t *volp, cm_vol_state_t *statep, 
+                                        afs_uint32 volID,  afs_uint32 *onlinep, 
+                                        afs_uint32 *volumeUpdatedp);
+ 
  extern void cm_UpdateVolumeStatus(cm_volume_t *volp, afs_uint32 volID);
  
  extern void cm_VolumeStatusNotification(cm_volume_t * volp, afs_uint32 volID, enum volstatus oldState, enum volstatus newState);
Index: openafs/src/WINNT/afsd/fs.c
diff -c openafs/src/WINNT/afsd/fs.c:1.32.4.23 openafs/src/WINNT/afsd/fs.c:1.32.4.25
*** openafs/src/WINNT/afsd/fs.c:1.32.4.23	Wed Aug  6 01:11:31 2008
--- openafs/src/WINNT/afsd/fs.c	Tue Sep  2 17:25:55 2008
***************
*** 3998,4005 ****
        flag = 1;
      else if (strcmp(tp, "off") == 0)
        flag = 0;
      else {
!       fprintf (stderr, "%s: %s must be \"on\" or \"off\".\n", pn, tp);
        return EINVAL;
      }
  
--- 3998,4007 ----
        flag = 1;
      else if (strcmp(tp, "off") == 0)
        flag = 0;
+     else if (strcmp(tp, "auth") == 0)
+       flag = 2;
      else {
!       fprintf (stderr, "%s: %s must be \"on\", \"auth\", or \"off\".\n", pn, tp);
        return EINVAL;
      }
  
***************
*** 4032,4038 ****
        tp = space;
        memcpy(&flag, tp, sizeof(afs_int32));
        printf("Security level is currently ");
!       if (flag == 1)
          printf("crypt (data security).\n");
        else
          printf("clear.\n");
--- 4034,4042 ----
        tp = space;
        memcpy(&flag, tp, sizeof(afs_int32));
        printf("Security level is currently ");
!       if (flag == 2)
!           printf("auth (data integrity).\n");
!       else if (flag == 1)
          printf("crypt (data security).\n");
        else
          printf("clear.\n");
Index: openafs/src/WINNT/afsd/smb.c
diff -c openafs/src/WINNT/afsd/smb.c:1.118.2.93 openafs/src/WINNT/afsd/smb.c:1.118.2.98
*** openafs/src/WINNT/afsd/smb.c:1.118.2.93	Thu Aug 14 13:25:06 2008
--- openafs/src/WINNT/afsd/smb.c	Wed Sep  3 16:41:04 2008
***************
*** 851,857 ****
          vcp->uidCounter = 1;  	/* UID 0 is reserved for blank user */
          vcp->nextp = smb_allVCsp;
          smb_allVCsp = vcp;
!         lock_InitializeMutex(&vcp->mx, "vc_t mutex");
          vcp->lsn = lsn;
          vcp->lana = lana;
          vcp->secCtx = NULL;
--- 851,857 ----
          vcp->uidCounter = 1;  	/* UID 0 is reserved for blank user */
          vcp->nextp = smb_allVCsp;
          smb_allVCsp = vcp;
!         lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
          vcp->lsn = lsn;
          vcp->lana = lana;
          vcp->secCtx = NULL;
***************
*** 884,890 ****
  
              if (ntsEx == STATUS_SUCCESS) {
                  memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
-                 LsaFreeReturnBuffer(lsaResp);
              } else {
                  /* 
                   * This will cause the subsequent authentication to fail but
--- 884,889 ----
***************
*** 893,898 ****
--- 892,899 ----
                   */
                  memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
              }
+             if (lsaResp)
+                 LsaFreeReturnBuffer(lsaResp);
          }
          else
              memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
***************
*** 1199,1205 ****
          tidp->vcp = vcp;
          smb_HoldVCNoLock(vcp);
          vcp->tidsp = tidp;
!         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
          tidp->tid = tid;
      }
  #ifdef DEBUG_SMB_REFCOUNT
--- 1200,1206 ----
          tidp->vcp = vcp;
          smb_HoldVCNoLock(vcp);
          vcp->tidsp = tidp;
!         lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
          tidp->tid = tid;
      }
  #ifdef DEBUG_SMB_REFCOUNT
***************
*** 1294,1300 ****
          uidp->vcp = vcp;
          smb_HoldVCNoLock(vcp);
          vcp->usersp = uidp;
!         lock_InitializeMutex(&uidp->mx, "user_t mutex");
          uidp->userID = uid;
          osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
  		 vcp, uidp->userID,
--- 1295,1301 ----
          uidp->vcp = vcp;
          smb_HoldVCNoLock(vcp);
          vcp->usersp = uidp;
!         lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
          uidp->userID = uid;
          osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
  		 vcp, uidp->userID,
***************
*** 1325,1331 ****
          unp->name = cm_ClientStrDup(usern);
          unp->machine = cm_ClientStrDup(machine);
          usernamesp = unp;
!         lock_InitializeMutex(&unp->mx, "username_t mutex");
  	if (flags & SMB_FLAG_AFSLOGON)
  	    unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
      }
--- 1326,1332 ----
          unp->name = cm_ClientStrDup(usern);
          unp->machine = cm_ClientStrDup(machine);
          usernamesp = unp;
!         lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
  	if (flags & SMB_FLAG_AFSLOGON)
  	    unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
      }
***************
*** 1571,1577 ****
          fidp->refCount = 1;
          fidp->vcp = vcp;
          smb_HoldVCNoLock(vcp);
!         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
          fidp->fid = fid;
          fidp->curr_chunk = fidp->prev_chunk = -2;
          fidp->raw_write_event = event;
--- 1572,1578 ----
          fidp->refCount = 1;
          fidp->vcp = vcp;
          smb_HoldVCNoLock(vcp);
!         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
          fidp->fid = fid;
          fidp->curr_chunk = fidp->prev_chunk = -2;
          fidp->raw_write_event = event;
***************
*** 1995,2001 ****
          if (code == 0) {
              clientchar_t temp[1024];
  
!             cm_FsStringToClientString(ftemp, (int)cm_FsStrLen(ftemp), temp, 1024);
              cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
                                  rw ? _C("/.%S/") : _C("/%S/"), temp);
              *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
--- 1996,2002 ----
          if (code == 0) {
              clientchar_t temp[1024];
  
!             cm_FsStringToClientString(ftemp, -1, temp, 1024);
              cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
                                  rw ? _C("/.%S/") : _C("/%S/"), temp);
              *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
***************
*** 2071,2079 ****
                  if (!smb_lastDirSearchp)
                      smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
              }
-             lock_ObtainMutex(&dsp->mx);
              dsp->refCount++;
-             lock_ReleaseMutex(&dsp->mx);
              break;
          }
      }
--- 2072,2078 ----
***************
*** 2089,2095 ****
  
  void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
  {
-     lock_ObtainWrite(&smb_globalLock);
      lock_ObtainMutex(&dsp->mx);
      osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
  	      dsp->cookie, dsp, dsp->scp);
--- 2088,2093 ----
***************
*** 2104,2110 ****
          lock_ReleaseWrite(&dsp->scp->rw);
      }	
      lock_ReleaseMutex(&dsp->mx);
-     lock_ReleaseWrite(&smb_globalLock);
  }               
  
  /* Must be called with the smb_globalLock held */
--- 2102,2107 ----
***************
*** 2112,2131 ****
  {
      cm_scache_t *scp = NULL;
  
-     lock_ObtainMutex(&dsp->mx);
      osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
!     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
!         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
!             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
!         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
!         lock_ReleaseMutex(&dsp->mx);
!         lock_FinalizeMutex(&dsp->mx);
!         scp = dsp->scp;
! 	osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
! 		 dsp->cookie, dsp, scp);
!         free(dsp);
!     } else {
!         lock_ReleaseMutex(&dsp->mx);
      }
      /* do this now to avoid spurious locking hierarchy creation */
      if (scp) 
--- 2109,2130 ----
  {
      cm_scache_t *scp = NULL;
  
      osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
!     if (dsp->refCount == 0) {
!         lock_ObtainMutex(&dsp->mx);
!         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
!             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
!                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
!             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
!             lock_ReleaseMutex(&dsp->mx);
!             lock_FinalizeMutex(&dsp->mx);
!             scp = dsp->scp;
!             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
!                      dsp->cookie, dsp, scp);
!             free(dsp);
!         } else {
!             lock_ReleaseMutex(&dsp->mx);
!         }
      }
      /* do this now to avoid spurious locking hierarchy creation */
      if (scp) 
***************
*** 2157,2184 ****
  void smb_GCDirSearches(int isV3)
  {
      smb_dirSearch_t *prevp;
!     smb_dirSearch_t *tp;
      smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
      int victimCount;
      int i;
          
      victimCount = 0;	/* how many have we got so far */
!     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
          /* we'll move tp from queue, so
           * do this early.
           */
!         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);	
          /* if no one is using this guy, and we're either in the new protocol,
           * or we're in the old one and this is a small enough ID to be useful
           * to the old protocol, GC this guy.
           */
!         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
              /* hold and delete */
! 	    lock_ObtainMutex(&tp->mx);
!             tp->flags |= SMB_DIRSEARCH_DELETE;
! 	    lock_ReleaseMutex(&tp->mx);
!             victimsp[victimCount++] = tp;
!             tp->refCount++;
          }
  
          /* don't do more than this */
--- 2156,2183 ----
  void smb_GCDirSearches(int isV3)
  {
      smb_dirSearch_t *prevp;
!     smb_dirSearch_t *dsp;
      smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
      int victimCount;
      int i;
          
      victimCount = 0;	/* how many have we got so far */
!     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
          /* we'll move tp from queue, so
           * do this early.
           */
!         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);	
          /* if no one is using this guy, and we're either in the new protocol,
           * or we're in the old one and this is a small enough ID to be useful
           * to the old protocol, GC this guy.
           */
!         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
              /* hold and delete */
! 	    lock_ObtainMutex(&dsp->mx);
!             dsp->flags |= SMB_DIRSEARCH_DELETE;
! 	    lock_ReleaseMutex(&dsp->mx);
!             victimsp[victimCount++] = dsp;
!             dsp->refCount++;
          }
  
          /* don't do more than this */
***************
*** 2238,2246 ****
              /* don't need to watch for refcount zero and deleted, since
              * we haven't dropped the global lock.
              */
-             lock_ObtainMutex(&dsp->mx);
              dsp->refCount--;
-             lock_ReleaseMutex(&dsp->mx);
              ++smb_dirSearchCounter;
              continue;
          }	
--- 2237,2243 ----
***************
*** 2250,2256 ****
          dsp->cookie = smb_dirSearchCounter;
          ++smb_dirSearchCounter;
          dsp->refCount = 1;
!         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
          dsp->lastTime = osi_Time();
          osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
          if (!smb_lastDirSearchp) 
--- 2247,2253 ----
          dsp->cookie = smb_dirSearchCounter;
          ++smb_dirSearchCounter;
          dsp->refCount = 1;
!         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
          dsp->lastTime = osi_Time();
          osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
          if (!smb_lastDirSearchp) 
***************
*** 2631,2637 ****
  #endif
          cb = sizeof(pktp->data);
      }
!     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
  }
  
  clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
--- 2628,2635 ----
  #endif
          cb = sizeof(pktp->data);
      }
!     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
!                               flags | SMB_STRF_SRCNULTERM);
  }
  
  clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
***************
*** 2727,2733 ****
          *stringspp = spacep;
  
          cchdest = lengthof(spacep->wdata);
!         cm_Utf8ToUtf16(inp, (int)*pcb_max, spacep->wdata, cchdest);
  
          return spacep->wdata;
  #ifdef SMB_UNICODE
--- 2725,2732 ----
          *stringspp = spacep;
  
          cchdest = lengthof(spacep->wdata);
!         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
!                        spacep->wdata, cchdest);
  
          return spacep->wdata;
  #ifdef SMB_UNICODE
***************
*** 5917,5922 ****
--- 5916,5923 ----
          /* if the call worked, stop doing the search now, since we
           * really only want to rename one file.
           */
+     if (code)
+         osi_Log0(smb_logp, "cm_Rename failure");
  	osi_Log1(smb_logp, "cm_Rename returns %ld", code);
      } else if (code == 0) {
          code = CM_ERROR_NOSUCHFILE;
***************
*** 7026,7037 ****
  
      lock_ObtainMutex(&fidp->mx);
      if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
!          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
          smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
                            fidp->NTopen_dscp, fidp->NTopen_pathp,
                            NULL, TRUE);
!     }       
!     lock_ReleaseMutex(&fidp->mx);
  
      if (code == 0) {
          if (smb_AsyncStore > 0) {
--- 7027,7041 ----
  
      lock_ObtainMutex(&fidp->mx);
      if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
!          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) 
!     {
!         lock_ReleaseMutex(&fidp->mx);
          smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
                            fidp->NTopen_dscp, fidp->NTopen_pathp,
                            NULL, TRUE);
!     } else {
!         lock_ReleaseMutex(&fidp->mx);
!     }
  
      if (code == 0) {
          if (smb_AsyncStore > 0) {
***************
*** 9449,9462 ****
      smb_logp = logp;
          
      /* and the global lock */
!     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
!     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
  
      /* Raw I/O data structures */
!     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
  
!     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
!     lock_InitializeMutex(&smb_StartedLock, "smb started lock");
  	
      /* 4 Raw I/O buffers */
      smb_RawBufs = calloc(65536,1);
--- 9453,9466 ----
      smb_logp = logp;
          
      /* and the global lock */
!     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
!     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
  
      /* Raw I/O data structures */
!     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
  
!     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
!     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
  	
      /* 4 Raw I/O buffers */
      smb_RawBufs = calloc(65536,1);
***************
*** 9859,9864 ****
--- 9863,9869 ----
              if (fidp->scp != NULL) {
                  cm_scache_t * scp;
  
+                 lock_ReleaseWrite(&smb_rctLock);
                  lock_ObtainMutex(&fidp->mx);
                  if (fidp->scp != NULL) {
                      scp = fidp->scp;
***************
*** 9870,9875 ****
--- 9875,9881 ----
                      cm_ReleaseSCache(scp);
                  }
                  lock_ReleaseMutex(&fidp->mx);
+                 lock_ObtainWrite(&smb_rctLock);
              }
          }
  
Index: openafs/src/WINNT/afsd/smb.h
diff -c openafs/src/WINNT/afsd/smb.h:1.41.2.36 openafs/src/WINNT/afsd/smb.h:1.41.2.37
*** openafs/src/WINNT/afsd/smb.h:1.41.2.36	Sat Aug  9 00:49:50 2008
--- openafs/src/WINNT/afsd/smb.h	Fri Aug 22 14:10:03 2008
***************
*** 649,654 ****
--- 649,655 ----
  #define SMB_STRF_FORCEASCII (1<<0)
  #define SMB_STRF_ANSIPATH   (1<<1)
  #define SMB_STRF_IGNORENUL  (1<<2)
+ #define SMB_STRF_SRCNULTERM (1<<3)
  
  extern clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
                                           char **chainpp, int flags);
Index: openafs/src/WINNT/afsd/smb3.c
diff -c openafs/src/WINNT/afsd/smb3.c:1.95.2.74 openafs/src/WINNT/afsd/smb3.c:1.95.2.79
*** openafs/src/WINNT/afsd/smb3.c:1.95.2.74	Sat Aug  9 00:49:50 2008
--- openafs/src/WINNT/afsd/smb3.c	Sat Sep 13 09:51:50 2008
***************
*** 2644,2650 ****
      case SMB_INFO_VOLUME: 
          /* volume info */
          qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
!         qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
  
          /* we're supposed to pad it out with zeroes to the end */
          memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
--- 2644,2650 ----
      case SMB_INFO_VOLUME: 
          /* volume info */
          qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
!         qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
  
          /* we're supposed to pad it out with zeroes to the end */
          memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
***************
*** 2663,2669 ****
          }
  
          qi.u.FSvolumeInfo.vsn = 1234;
!         qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
          memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
          break;
  
--- 2663,2670 ----
          }
  
          qi.u.FSvolumeInfo.vsn = 1234;
!         qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
!         memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
          memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
          break;
  
***************
*** 3070,3076 ****
  	qpi.u.QPfileBasicInfo.reserved = 0;
      }
      else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
! 	smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
  
          qpi.u.QPfileStandardInfo.allocationSize = scp->length;
          qpi.u.QPfileStandardInfo.endOfFile = scp->length;
--- 3071,3081 ----
  	qpi.u.QPfileBasicInfo.reserved = 0;
      }
      else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
! 	smb_fid_t * fidp;
!             
!         lock_ReleaseRead(&scp->rw);
!         scp_rw_held = 0;
!         fidp = smb_FindFIDByScache(vcp, scp);
  
          qpi.u.QPfileStandardInfo.allocationSize = scp->length;
          qpi.u.QPfileStandardInfo.endOfFile = scp->length;
***************
*** 3082,3089 ****
          qpi.u.QPfileStandardInfo.reserved = 0;
  
      	if (fidp) {
- 	    lock_ReleaseRead(&scp->rw);
- 	    scp_rw_held = 0;
  	    lock_ObtainMutex(&fidp->mx);
  	    delonclose = fidp->flags & SMB_FID_DELONCLOSE;
  	    lock_ReleaseMutex(&fidp->mx);
--- 3087,3092 ----
***************
*** 6002,6008 ****
              for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
              {
                  for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
!                     if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
                          LargeIntegerEqualTo(wl->LLength, LLength)) {
                          wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
                          goto found_lock_request;
--- 6005,6011 ----
              for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
              {
                  for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
!                     if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
                          LargeIntegerEqualTo(wl->LLength, LLength)) {
                          wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
                          goto found_lock_request;
***************
*** 6645,6650 ****
--- 6648,6659 ----
  #define FILE_RANDOM_ACCESS        0x0800
  #define FILE_DELETE_ON_CLOSE      0x1000
  #define FILE_OPEN_BY_FILE_ID      0x2000
+ #define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
+ #define FILE_NO_COMPRESSION                     0x00008000
+ #define FILE_RESERVE_OPFILTER                   0x00100000
+ #define FILE_OPEN_REPARSE_POINT                 0x00200000
+ #define FILE_OPEN_NO_RECALL                     0x00400000
+ #define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
  
  /* SMB_COM_NT_CREATE_ANDX */
  long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
***************
*** 6686,6691 ****
--- 6695,6702 ----
      BOOL foundscp;
      cm_req_t req;
      int created = 0;
+     int prefetch = 0;
+     int checkDoneRequired = 0;
      cm_lock_data_t *ldp = NULL;
  
      smb_InitReq(&req);
***************
*** 6870,6875 ****
--- 6881,6888 ----
  	fidflags |= SMB_FID_SEQUENTIAL;
      if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
  	fidflags |= SMB_FID_RANDOM;
+     if (createOptions & FILE_OPEN_REPARSE_POINT)
+         osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
      if (smb_IsExecutableFileName(lastNamep))
          fidflags |= SMB_FID_EXECUTABLE;
  
***************
*** 7078,7083 ****
--- 7091,7097 ----
      if (code == 0 && !treeCreate) {
          code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
          if (code) {
+             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              if (dscp)
                  cm_ReleaseSCache(dscp);
              if (scp)
***************
*** 7086,7091 ****
--- 7100,7106 ----
              free(realPathp);
              return code;
          }
+         checkDoneRequired = 1;
  
  	if (createDisp == FILE_CREATE) {
              /* oops, file shouldn't be there */
***************
*** 7123,7128 ****
--- 7138,7144 ----
                      scp = targetScp;
  		    code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
  		    if (code) {
+                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
  			if (dscp)
  			    cm_ReleaseSCache(dscp);
  			if (scp)
***************
*** 7287,7293 ****
  
      if (code) {
          /* something went wrong creating or truncating the file */
! 	if (ldp)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
          if (scp) 
              cm_ReleaseSCache(scp);
--- 7303,7309 ----
  
      if (code) {
          /* something went wrong creating or truncating the file */
! 	if (checkDoneRequired)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
          if (scp) 
              cm_ReleaseSCache(scp);
***************
*** 7311,7325 ****
                  * we'll just use the symlink anyway.
                  */
                  osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
! 		if (ldp)
  		    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                  cm_ReleaseSCache(scp);
                  scp = targetScp;
              }
          }
  
          if (scp->fileType != CM_SCACHETYPE_FILE) {
! 	    if (ldp)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              if (dscp)
                  cm_ReleaseSCache(dscp);
--- 7327,7343 ----
                  * we'll just use the symlink anyway.
                  */
                  osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
! 		if (checkDoneRequired) {
  		    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                     checkDoneRequired = 0;
+                 }
                  cm_ReleaseSCache(scp);
                  scp = targetScp;
              }
          }
  
          if (scp->fileType != CM_SCACHETYPE_FILE) {
! 	    if (checkDoneRequired)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              if (dscp)
                  cm_ReleaseSCache(dscp);
***************
*** 7332,7338 ****
  
      /* (only applies to single component case) */
      if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
! 	if (ldp)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
          cm_ReleaseSCache(scp);
          if (dscp)
--- 7350,7356 ----
  
      /* (only applies to single component case) */
      if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
! 	if (checkDoneRequired)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
          cm_ReleaseSCache(scp);
          if (dscp)
***************
*** 7381,7387 ****
          lock_ReleaseWrite(&scp->rw);
  
          if (code) {
! 	    if (ldp)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              cm_ReleaseSCache(scp);
              if (dscp)
--- 7399,7405 ----
          lock_ReleaseWrite(&scp->rw);
  
          if (code) {
! 	    if (checkDoneRequired)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              cm_ReleaseSCache(scp);
              if (dscp)
***************
*** 7396,7403 ****
      }
  
      /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
!     if (ldp)
  	cm_CheckNTOpenDone(scp, userp, &req, &ldp);
  
      lock_ObtainMutex(&fidp->mx);
      /* save a pointer to the vnode */
--- 7414,7423 ----
      }
  
      /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
!     if (checkDoneRequired) {
  	cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+         checkDoneRequired = 0;
+     }
  
      lock_ObtainMutex(&fidp->mx);
      /* save a pointer to the vnode */
***************
*** 7461,7471 ****
      if ((fidp->flags & SMB_FID_EXECUTABLE) && 
          LargeIntegerGreaterThanZero(fidp->scp->length) && 
          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
          cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
                             fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
                             userp);
!     }
!     lock_ReleaseRead(&scp->rw);
  
      osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
                osi_LogSaveClientString(smb_logp, realPathp));
--- 7481,7495 ----
      if ((fidp->flags & SMB_FID_EXECUTABLE) && 
          LargeIntegerGreaterThanZero(fidp->scp->length) && 
          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+         prefetch = 1;
+     }
+     lock_ReleaseRead(&scp->rw);
+ 
+     if (prefetch)
          cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
                             fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
                             userp);
! 
  
      osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
                osi_LogSaveClientString(smb_logp, realPathp));
***************
*** 7505,7519 ****
      unsigned int extendedRespRequired;
      int realDirFlag;
      unsigned int desiredAccess;
- #ifdef DEBUG_VERBOSE    
      unsigned int allocSize;
- #endif
      unsigned int shareAccess;
      unsigned int extAttributes;
      unsigned int createDisp;
- #ifdef DEBUG_VERBOSE
      unsigned int sdLen;
! #endif
      unsigned int createOptions;
      int initialModeBits;
      unsigned short baseFid;
--- 7529,7542 ----
      unsigned int extendedRespRequired;
      int realDirFlag;
      unsigned int desiredAccess;
      unsigned int allocSize;
      unsigned int shareAccess;
      unsigned int extAttributes;
      unsigned int createDisp;
      unsigned int sdLen;
!     unsigned int eaLen;
!     unsigned int impLevel;
!     unsigned int secFlags;
      unsigned int createOptions;
      int initialModeBits;
      unsigned short baseFid;
***************
*** 7532,7538 ****
--- 7555,7563 ----
      char *outData;
      cm_req_t req;
      int created = 0;
+     int prefetch = 0;
      cm_lock_data_t *ldp = NULL;
+     int checkDoneRequired = 0;
  
      smb_InitReq(&req);
  
***************
*** 7558,7580 ****
          return CM_ERROR_INVAL;
      baseFid = (unsigned short)lparmp[1];
      desiredAccess = lparmp[2];
- #ifdef DEBUG_VERBOSE
      allocSize = lparmp[3];
- #endif /* DEBUG_VERSOSE */
      extAttributes = lparmp[5];
      shareAccess = lparmp[6];
      createDisp = lparmp[7];
      createOptions = lparmp[8];
- #ifdef DEBUG_VERBOSE
      sdLen = lparmp[9];
! #endif
!     nameLength = lparmp[11];
! 
! #ifdef DEBUG_VERBOSE
!     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
!     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
!     osi_Log1(smb_logp,"... flags[%x]",flags);
! #endif
  
      /* mustBeDir is never set; createOptions directory bit seems to be
       * more important
--- 7583,7598 ----
          return CM_ERROR_INVAL;
      baseFid = (unsigned short)lparmp[1];
      desiredAccess = lparmp[2];
      allocSize = lparmp[3];
      extAttributes = lparmp[5];
      shareAccess = lparmp[6];
      createDisp = lparmp[7];
      createOptions = lparmp[8];
      sdLen = lparmp[9];
!     eaLen = lparmp[10];
!     nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
!     impLevel = lparmp[12];
!     secFlags = lparmp[13];
  
      /* mustBeDir is never set; createOptions directory bit seems to be
       * more important
***************
*** 7594,7608 ****
      if (extAttributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~0222;
  
!     pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
                                 nameLength, NULL, SMB_STRF_ANSIPATH);
!     /* Sometimes path is not null-terminated, so we make a copy. */
!     realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
!     memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
!     realPathp[nameLength] = 0;
      spacep = cm_GetSpace();
      smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
  
      /*
       * Nothing here to handle SMB_IOCTL_FILENAME.
       * Will add it if necessary.
--- 7612,7631 ----
      if (extAttributes & SMB_ATTR_READONLY) 
          initialModeBits &= ~0222;
  
!     pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
                                 nameLength, NULL, SMB_STRF_ANSIPATH);
!     /* Sometimes path is not nul-terminated, so we make a copy. */
!     realPathp = malloc(nameLength+sizeof(clientchar_t));
!     memcpy(realPathp, pathp, nameLength);
!     realPathp[nameLength/sizeof(clientchar_t)] = 0;
      spacep = cm_GetSpace();
      smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
  
+     osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
+     osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
+     osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
+     osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
+ 
      /*
       * Nothing here to handle SMB_IOCTL_FILENAME.
       * Will add it if necessary.
***************
*** 7677,7682 ****
--- 7700,7707 ----
  	fidflags |= SMB_FID_SEQUENTIAL;
      if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
  	fidflags |= SMB_FID_RANDOM;
+     if (createOptions & FILE_OPEN_REPARSE_POINT)
+         osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
      if (smb_IsExecutableFileName(lastNamep))
          fidflags |= SMB_FID_EXECUTABLE;
  
***************
*** 7819,7824 ****
--- 7844,7850 ----
      if (code == 0) {
          code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
          if (code) {     
+             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              if (dscp) 
                  cm_ReleaseSCache(dscp);
              cm_ReleaseSCache(scp);
***************
*** 7826,7831 ****
--- 7852,7858 ----
              free(realPathp);
              return code;
          }
+         checkDoneRequired = 1;
  
          if (createDisp == FILE_CREATE) {
              /* oops, file shouldn't be there */
***************
*** 7861,7866 ****
--- 7888,7894 ----
                      scp = targetScp;
  		    code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
  		    if (code) {
+                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
  			if (dscp)
  			    cm_ReleaseSCache(dscp);
  			if (scp)
***************
*** 7963,7969 ****
  
      if (code) {
          /* something went wrong creating or truncating the file */
! 	if (ldp)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
  	if (scp) 
              cm_ReleaseSCache(scp);
--- 7991,7997 ----
  
      if (code) {
          /* something went wrong creating or truncating the file */
! 	if (checkDoneRequired)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
  	if (scp) 
              cm_ReleaseSCache(scp);
***************
*** 7986,8000 ****
                  */
                  osi_Log2(smb_logp, "symlink vp %x to vp %x",
                            scp, targetScp);
! 		if (ldp)
  		    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                  cm_ReleaseSCache(scp);
                  scp = targetScp;
              }
          }
  
          if (scp->fileType != CM_SCACHETYPE_FILE) {
! 	    if (ldp)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
--- 8014,8030 ----
                  */
                  osi_Log2(smb_logp, "symlink vp %x to vp %x",
                            scp, targetScp);
! 		if (checkDoneRequired) {
  		    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                     checkDoneRequired = 0;
+                 }
                  cm_ReleaseSCache(scp);
                  scp = targetScp;
              }
          }
  
          if (scp->fileType != CM_SCACHETYPE_FILE) {
! 	    if (checkDoneRequired)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
***************
*** 8004,8010 ****
      }
  
      if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
! 	if (ldp)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
          cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
--- 8034,8040 ----
      }
  
      if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
! 	if (checkDoneRequired)
  	    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
          cm_ReleaseSCache(scp);
          cm_ReleaseUser(userp);
***************
*** 8049,8055 ****
          lock_ReleaseWrite(&scp->rw);
  
          if (code) {
! 	    if (ldp)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
--- 8079,8085 ----
          lock_ReleaseWrite(&scp->rw);
  
          if (code) {
! 	    if (checkDoneRequired)
  		cm_CheckNTOpenDone(scp, userp, &req, &ldp);
              cm_ReleaseSCache(scp);
              cm_ReleaseUser(userp);
***************
*** 8062,8069 ****
      }
  
      /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
!     if (ldp)
  	cm_CheckNTOpenDone(scp, userp, &req, &ldp);
  
      lock_ObtainMutex(&fidp->mx);
      /* save a pointer to the vnode */
--- 8092,8101 ----
      }
  
      /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
!     if (checkDoneRequired) {
  	cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+         checkDoneRequired = 0;
+     }
  
      lock_ObtainMutex(&fidp->mx);
      /* save a pointer to the vnode */
***************
*** 8206,8216 ****
      if ((fidp->flags & SMB_FID_EXECUTABLE) && 
           LargeIntegerGreaterThanZero(fidp->scp->length) && 
           !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
          cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
                             fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
                             userp);
-     }
-     lock_ReleaseRead(&scp->rw);
  
      osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
  
--- 8238,8251 ----
      if ((fidp->flags & SMB_FID_EXECUTABLE) && 
           LargeIntegerGreaterThanZero(fidp->scp->length) && 
           !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+         prefetch = 1;
+     }
+     lock_ReleaseRead(&scp->rw);
+ 
+     if (prefetch)
          cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
                             fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
                             userp);
  
      osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
  
***************
*** 8511,8522 ****
              (!isDirectParent && !wtree)) 
          {
              osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
-             smb_ReleaseFID(fidp);
              lastWatch = watch;
              watch = watch->nextp;
              continue;
          }
-         smb_ReleaseFID(fidp);
  
          osi_Log4(smb_logp,
                    "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
--- 8546,8558 ----
              (!isDirectParent && !wtree)) 
          {
              osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
              lastWatch = watch;
              watch = watch->nextp;
+             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+             smb_ReleaseFID(fidp);
+             lock_ObtainMutex(&smb_Dir_Watch_Lock);
              continue;
          }
  
          osi_Log4(smb_logp,
                    "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
***************
*** 8553,8558 ****
--- 8589,8597 ----
          else
              lastWatch->nextp = nextWatch;
  
+         /* The watch is off the list, its ours now, safe to drop the lock */
+         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+ 
          /* Turn off WATCHED flag in dscp */
          lock_ObtainWrite(&dscp->rw);
          if (wtree)
***************
*** 8653,8658 ****
--- 8692,8700 ----
  
          smb_SendPacket(watch->vcp, watch);
          smb_FreePacket(watch);
+ 
+         smb_ReleaseFID(fidp);
+         lock_ObtainMutex(&smb_Dir_Watch_Lock);
          watch = nextWatch;
      }
      lock_ReleaseMutex(&smb_Dir_Watch_Lock);
***************
*** 8763,8781 ****
      osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
               osi_LogSaveClientString(smb_logp, oldPathp),
               osi_LogSaveClientString(smb_logp, newPathp),
!              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
  
      if (rename_type == RENAME_FLAG_RENAME) {
          code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
!     } else { /* RENAME_FLAG_HARD_LINK */
          code = smb_Link(vcp,inp,oldPathp,newPathp);
!     }
      return code;
  }
  
  void smb3_Init()
  {
!     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
  }
  
  cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
--- 8805,8824 ----
      osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
               osi_LogSaveClientString(smb_logp, oldPathp),
               osi_LogSaveClientString(smb_logp, newPathp),
!              ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
  
      if (rename_type == RENAME_FLAG_RENAME) {
          code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
!     } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
          code = smb_Link(vcp,inp,oldPathp,newPathp);
!     } else 
!         code = CM_ERROR_BADOP;
      return code;
  }
  
  void smb3_Init()
  {
!     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
  }
  
  cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
Index: openafs/src/WINNT/afsd/smb_ioctl.c
diff -c openafs/src/WINNT/afsd/smb_ioctl.c:1.25.2.16 openafs/src/WINNT/afsd/smb_ioctl.c:1.25.2.17
*** openafs/src/WINNT/afsd/smb_ioctl.c:1.25.2.16	Sat Jul 26 22:48:11 2008
--- openafs/src/WINNT/afsd/smb_ioctl.c	Tue Sep  2 17:21:35 2008
***************
*** 1064,1071 ****
          int cch;
  
          cch = cm_ClientStringToUtf8(uidp->unp->name,
!                                     cm_ClientStrLen(uidp->unp->name),
! 
                                      ioctlp->ioctl.outDatap,
                                      (SMB_IOCTL_MAXDATA -
                                       (ioctlp->ioctl.outDatap - ioctlp->ioctl.outAllocp))
--- 1064,1070 ----
          int cch;
  
          cch = cm_ClientStringToUtf8(uidp->unp->name,
!                                     -1,
                                      ioctlp->ioctl.outDatap,
                                      (SMB_IOCTL_MAXDATA -
                                       (ioctlp->ioctl.outDatap - ioctlp->ioctl.outAllocp))
Index: openafs/src/WINNT/client_creds/main.cpp
diff -c openafs/src/WINNT/client_creds/main.cpp:1.16.4.2 openafs/src/WINNT/client_creds/main.cpp:1.16.4.3
*** openafs/src/WINNT/client_creds/main.cpp:1.16.4.2	Mon Feb 11 11:44:27 2008
--- openafs/src/WINNT/client_creds/main.cpp	Fri Aug 22 14:10:08 2008
***************
*** 254,261 ****
     InitCommonControls();
     RegisterCheckListClass();
     osi_Init();
!    lock_InitializeMutex(&g.expirationCheckLock, "expiration check lock");
!    lock_InitializeMutex(&g.credsLock, "global creds lock");
  
     KFW_AFS_wait_for_service_start();
  
--- 254,261 ----
     InitCommonControls();
     RegisterCheckListClass();
     osi_Init();
!    lock_InitializeMutex(&g.expirationCheckLock, "expiration check lock", 0);
!    lock_InitializeMutex(&g.credsLock, "global creds lock", 0);
  
     KFW_AFS_wait_for_service_start();
  
Index: openafs/src/WINNT/client_osi/libosi.def
diff -c openafs/src/WINNT/client_osi/libosi.def:1.3.14.3 openafs/src/WINNT/client_osi/libosi.def:1.3.14.4
*** openafs/src/WINNT/client_osi/libosi.def:1.3.14.3	Thu Jun 26 12:00:53 2008
--- openafs/src/WINNT/client_osi/libosi.def	Sat Aug 30 10:05:14 2008
***************
*** 72,74 ****
--- 72,75 ----
          osi_QRemoveHT           @65
  	lock_ConvertRToW	@66
          osi_LogSaveStringW      @67
+         osi_SetLockOrderValidation @68
Index: openafs/src/WINNT/client_osi/osi.h
diff -c openafs/src/WINNT/client_osi/osi.h:1.5.14.1 openafs/src/WINNT/client_osi/osi.h:1.5.14.2
*** openafs/src/WINNT/client_osi/osi.h:1.5.14.1	Mon Sep 10 15:02:39 2007
--- openafs/src/WINNT/client_osi/osi.h	Fri Aug 22 14:10:08 2008
***************
*** 17,31 ****
  /* misc definitions */
  
  /* large int */
- #ifndef DJGPP
  #include <rpc.h>
  #if !defined(_MSC_VER) || (_MSC_VER < 1300)
  #include "largeint.h"
  #endif
  #include "osithrdnt.h"
- #else /* DJGPP */
- #include "largeint95.h"
- #endif /* !DJGPP */
  
  typedef LARGE_INTEGER osi_hyper_t;
  #if _MSC_VER >= 1300
--- 17,27 ----
***************
*** 62,76 ****
  
  #define LargeIntegerNotEqualToZero(a) ((a).HighPart || (a).LowPart)
  #endif
- #ifndef DJGPP
  typedef GUID osi_uid_t;
- #else /* DJGPP */
- typedef int osi_uid_t;
- #endif /* !DJGPP */
- 
  typedef int int32;
  
- #ifndef DJGPP
  /* basic util functions */
  #include "osiutils.h"
  
--- 58,66 ----
***************
*** 79,90 ****
  
  /* lock type definitions */
  #include "osiltype.h"
- #endif /* !DJGPP */
  
  /* basic sleep operations */
  #include "osisleep.h"
  
- #ifndef DJGPP
  /* base lock definitions */
  #include "osibasel.h"
  
--- 69,78 ----
***************
*** 93,101 ****
  
  /* RPC debug stuff */
  #include "osidb.h"
- #else /* DJGPP */
- #include "osithrd95.h"
- #endif /* !DJGPP */
  
  /* log stuff */
  #include "osilog.h"
--- 81,86 ----
Index: openafs/src/WINNT/client_osi/osibasel.c
diff -c openafs/src/WINNT/client_osi/osibasel.c:1.4.4.3 openafs/src/WINNT/client_osi/osibasel.c:1.4.4.6
*** openafs/src/WINNT/client_osi/osibasel.c:1.4.4.3	Wed Feb 27 12:06:44 2008
--- openafs/src/WINNT/client_osi/osibasel.c	Sat Aug 30 10:05:14 2008
***************
*** 16,549 ****
  #include <windows.h>
  #include "osi.h"
  #include <assert.h>
  
  /* atomicity-providing critical sections */
  CRITICAL_SECTION osi_baseAtomicCS[OSI_MUTEXHASHSIZE];
  static long     atomicIndexCounter = 0;
  
  void osi_BaseInit(void)
  {
! 	int i;
! 
!         for(i=0; i<OSI_MUTEXHASHSIZE; i++)
! 		InitializeCriticalSection(&osi_baseAtomicCS[i]);
! }
  
! void lock_ObtainWrite(osi_rwlock_t *lockp)
! {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i=lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ObtainWriteProc)(lockp);
! 	    return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)
! 		|| (lockp->readers > 0)) {
!                 lockp->waiters++;
! 		osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
!                 lockp->waiters--;
! 		osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
! 	}
!         else {
! 		/* if we're here, all clear to set the lock */
! 		lockp->flags |= OSI_LOCKFLAG_EXCL;
! 	}
  
!         lockp->tid = thrd_Current();
  
! 	LeaveCriticalSection(csp);
  }
  
! void lock_ObtainRead(osi_rwlock_t *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i=lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ObtainReadProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
! 		lockp->waiters++;
! 		osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
! 		lockp->waiters--;
! 		osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
! 	}
!         else {
! 		/* if we're here, all clear to set the lock */
! 		lockp->readers++;
! 	}
  
!         LeaveCriticalSection(csp);
  }
  
! void lock_ReleaseRead(osi_rwlock_t *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ReleaseReadProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	osi_assertx(lockp->readers > 0, "read lock not held");
! 	
! 	/* releasing a read lock can allow readers or writers */
! 	if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, 0, csp);
! 	}
!         else {
! 		/* and finally release the big lock */
! 		LeaveCriticalSection(csp);
! 	}
  }
  
! void lock_ReleaseWrite(osi_rwlock_t *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ReleaseWriteProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
  
! 	osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
! 	
!         lockp->tid = 0;
  
! 	lockp->flags &= ~OSI_LOCKFLAG_EXCL;
! 	if (!osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, 0, csp);
! 	}
! 	else {
! 		/* and finally release the big lock */
! 		LeaveCriticalSection(csp);
! 	}
  }
  
! void lock_ConvertWToR(osi_rwlock_t *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ConvertWToRProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
  
! 	osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
! 	
! 	/* convert write lock to read lock */
! 	lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!         lockp->readers++;
  
!         lockp->tid = 0;
  
! 	if (!osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
! 	}
!         else {
! 		/* and finally release the big lock */
! 		LeaveCriticalSection(csp);
! 	}
  }
  
  void lock_ConvertRToW(osi_rwlock_t *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ConvertRToWProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	osi_assertx(!(lockp->flags & OSI_LOCKFLAG_EXCL), "write lock held");
!         osi_assertx(lockp->readers > 0, "read lock not held");
! 	
!         if (--lockp->readers == 0) {
!             /* convert read lock to write lock */
!             lockp->flags |= OSI_LOCKFLAG_EXCL;
!         } else {
!             lockp->waiters++;
!             osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
!             lockp->waiters--;
!             osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
! 	}
  
!         lockp->tid = thrd_Current();
!         LeaveCriticalSection(csp);
! }
  
  void lock_ObtainMutex(struct osi_mutex *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i=lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ObtainMutexProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
!         	lockp->waiters++;
! 		osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
!                 lockp->waiters--;
! 		osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
! 	}
!         else {
! 		/* if we're here, all clear to set the lock */
! 		lockp->flags |= OSI_LOCKFLAG_EXCL;
! 	}
!         lockp->tid = thrd_Current();
! 	LeaveCriticalSection(csp);
  }
  
  void lock_ReleaseMutex(struct osi_mutex *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->ReleaseMutexProc)(lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
! 	
! 	lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!         lockp->tid = 0;
! 	if (!osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, 0, csp);
! 	}
! 	else {
! 		/* and finally release the big lock */
! 		LeaveCriticalSection(csp);
! 	}
! }
  
  int lock_TryRead(struct osi_rwlock *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i=lockp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		return (osi_lockOps[i]->TryReadProc)(lockp);
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
! 		i = 0;
! 	}
! 	else {
! 		/* if we're here, all clear to set the lock */
! 		lockp->readers++;
! 		i = 1;
! 	}
  
! 	LeaveCriticalSection(csp);
  
! 	return i;
! }
  
  
  int lock_TryWrite(struct osi_rwlock *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i=lockp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		return (osi_lockOps[i]->TryWriteProc)(lockp);
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)
! 		|| (lockp->readers > 0)) {
! 		i = 0;
! 	}
! 	else {
! 		/* if we're here, all clear to set the lock */
! 		lockp->flags |= OSI_LOCKFLAG_EXCL;
! 		i = 1;
! 	}
  
! 	if (i)
! 	    lockp->tid = thrd_Current();
  
!         LeaveCriticalSection(csp);
  
! 	return i;
  }
  
  
  int lock_TryMutex(struct osi_mutex *lockp) {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i=lockp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		return (osi_lockOps[i]->TryMutexProc)(lockp);
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
! 		i = 0;
! 	}
! 	else {
! 		/* if we're here, all clear to set the lock */
! 		lockp->flags |= OSI_LOCKFLAG_EXCL;
! 		i = 1;
! 	}
  
!         if (i)
! 	    lockp->tid = thrd_Current();
  
! 	LeaveCriticalSection(csp);
  
! 	return i;
  }
  
  void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
! 	
! 	/* XXX better to get the list of things to wakeup from TSignalForMLs, and
!          * then do the wakeup after SleepSpin releases the low-level mutex.
!          */
! 	if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
! 	}
! 
! 	/* now call into scheduler to sleep atomically with releasing spin lock */
! 	osi_SleepSpin(sleepVal, csp);
! }
  
  void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
! 
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->SleepWProc)(sleepVal, lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
! 	
! 	lockp->flags &= ~OSI_LOCKFLAG_EXCL;
! 	if (!osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
! 	}
  
! 	/* and finally release the big lock */
! 	osi_SleepSpin(sleepVal, csp);
  }
  
  void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i = lockp->type) != 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
! 		return;
! 	}
! 
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lockp->atomicIndex];
!         EnterCriticalSection(csp);
! 
! 	osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
  	
! 	lockp->flags &= ~OSI_LOCKFLAG_EXCL;
! 	if (!osi_TEmpty(&lockp->d.turn)) {
! 		osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
! 	}
  
! 	/* and finally release the big lock */
! 	osi_SleepSpin(sleepVal, csp);
  }
  
  void lock_FinalizeRWLock(osi_rwlock_t *lockp)
  {
! 	long i;
  
! 	if ((i=lockp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->FinalizeRWLockProc)(lockp);
! }
  
  void lock_FinalizeMutex(osi_mutex_t *lockp)
! {
! 	long i;
! 
! 	if ((i=lockp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->FinalizeMutexProc)(lockp);
! }
! 
! void lock_InitializeMutex(osi_mutex_t *mp, char *namep)
! {
! 	int i;
  
! 	if ((i = osi_lockTypeDefault) > 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->InitializeMutexProc)(mp, namep);
! 		return;
! 	}
! 
! 	/* otherwise we have the base case, which requires no special
! 	 * initialization.
! 	 */
! 	mp->type = 0;
! 	mp->flags = 0;
!         mp->tid = 0;
! 	mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
!         osi_TInit(&mp->d.turn);
! 	return;
! }
! 
! void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep)
! {
! 	int i;
! 
! 	if ((i = osi_lockTypeDefault) > 0) {
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		(osi_lockOps[i]->InitializeRWLockProc)(mp, namep);
! 		return;
! 	}
  	
! 	/* otherwise we have the base case, which requires no special
! 	 * initialization.
! 	 */
! 	mp->type = 0;
! 	mp->flags = 0;
!         mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
! 	mp->readers = 0;
!         mp->tid = 0;
!         osi_TInit(&mp->d.turn);
! 	return;
  }
  
  int lock_GetRWLockState(osi_rwlock_t *lp)
  {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i=lp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		return (osi_lockOps[i]->GetRWLockState)(lp);
  
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[lp->atomicIndex];
!         EnterCriticalSection(csp);
  
! 	/* here we have the fast lock, so see if we can obtain the real lock */
! 	if (lp->flags & OSI_LOCKFLAG_EXCL) i = OSI_RWLOCK_WRITEHELD;
!         else i = 0;
! 	if (lp->readers > 0) i |= OSI_RWLOCK_READHELD;
  
! 	LeaveCriticalSection(csp);
  
! 	return i;
  }
  
! int lock_GetMutexState(struct osi_mutex *mp) {
! 	long i;
!         CRITICAL_SECTION *csp;
  
! 	if ((i=mp->type) != 0)
! 	    if (i >= 0 && i < OSI_NLOCKTYPES)
! 		return (osi_lockOps[i]->GetMutexState)(mp);
  
! 	/* otherwise we're the fast base type */
! 	csp = &osi_baseAtomicCS[mp->atomicIndex];
!         EnterCriticalSection(csp);
  
! 	if (mp->flags & OSI_LOCKFLAG_EXCL)
!         	i = OSI_MUTEX_HELD;
! 	else
!         	i = 0;
  
! 	LeaveCriticalSection(csp);
  
! 	return i;
  }
--- 16,881 ----
  #include <windows.h>
  #include "osi.h"
  #include <assert.h>
+ #include <stdio.h>
  
  /* atomicity-providing critical sections */
  CRITICAL_SECTION osi_baseAtomicCS[OSI_MUTEXHASHSIZE];
  static long     atomicIndexCounter = 0;
  
+ /* Thread local storage index for lock tracking */
+ static DWORD tls_LockRefH = 0;
+ static DWORD tls_LockRefT = 0;
+ static BOOLEAN lockOrderValidation = 0;
+ 
  void osi_BaseInit(void)
  {
!     int i;
  
!     for(i=0; i<OSI_MUTEXHASHSIZE; i++)
!         InitializeCriticalSection(&osi_baseAtomicCS[i]);
  
!     if ((tls_LockRefH = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
!         osi_panic("TlsAlloc(tls_LockRefH) failure", __FILE__, __LINE__); 
  
!     if ((tls_LockRefT = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
!         osi_panic("TlsAlloc(tls_LockRefT) failure", __FILE__, __LINE__); 
! }       
  
! void osi_SetLockOrderValidation(int on)
! {
!     lockOrderValidation = (BOOLEAN)on;
  }
  
! osi_lock_ref_t *lock_GetLockRef(void * lockp, char type)
  {
!     osi_lock_ref_t * lockRefp = (osi_lock_ref_t *)malloc(sizeof(osi_lock_ref_t));
  
!     memset(lockRefp, 0, sizeof(osi_lock_ref_t));
!     lockRefp->type = type;
!     switch (type) {
!     case OSI_LOCK_MUTEX:
!         lockRefp->mx = lockp;
!         break;
!     case OSI_LOCK_RW:
!         lockRefp->rw = lockp;
!         break;
!     default:
!         osi_panic("Invalid Lock Type", __FILE__, __LINE__);
!     }
  
!     return lockRefp;
  }
  
! void lock_VerifyOrderRW(osi_queue_t *lockRefH, osi_queue_t *lockRefT, osi_rwlock_t *lockp)
  {
!     char msg[512];
!     osi_lock_ref_t * lockRefp;
  
!     for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!         if (lockRefp->type == OSI_LOCK_RW) {
!             if (lockRefp->rw == lockp) {
!                 sprintf(msg, "RW Lock 0x%p level %d already held", lockp, lockp->level);
!                 osi_panic(msg, __FILE__, __LINE__);
!             }
!             if (lockRefp->rw->level > lockp->level) {
!                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
!                          lockRefp->rw, lockRefp->rw->level, lockp, lockp->level);
!                 osi_panic(msg, __FILE__, __LINE__);
!             }
!         } else {
!             if (lockRefp->mx->level > lockp->level) {
!                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
!                          lockRefp->mx, lockRefp->mx->level, lockp, lockp->level);
!                 osi_panic(msg, __FILE__, __LINE__);
!             }
!             osi_assertx(lockRefp->mx->level <= lockp->level, "Lock hierarchy violation");
!         }
!     }
! }
! 
! void lock_VerifyOrderMX(osi_queue_t *lockRefH, osi_queue_t *lockRefT, osi_mutex_t *lockp)
! {
!     char msg[512];
!     osi_lock_ref_t * lockRefp;
! 
!     for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!         if (lockRefp->type == OSI_LOCK_MUTEX) {
!             if (lockRefp->mx == lockp) {
!                 sprintf(msg, "MX Lock 0x%p level %d already held", lockp, lockp->level);
!                 osi_panic(msg, __FILE__, __LINE__);
!             }
!             if (lockRefp->mx->level > lockp->level) {
!                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
!                          lockRefp->mx, lockRefp->mx->level, lockp, lockp->level);
!                 osi_panic(msg, __FILE__, __LINE__);
!             }
!         } else {
!             if (lockRefp->rw->level > lockp->level) {
!                 sprintf(msg, "Lock hierarchy violation Held lock 0x%p level %d > Requested lock 0x%p level %d",
!                          lockRefp->rw, lockRefp->rw->level, lockp, lockp->level);
!                 osi_panic(msg, __FILE__, __LINE__);
!             }
!         }
!     }
  }
  
! void lock_ObtainWrite(osi_rwlock_t *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
!         
!     if ((i=lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ObtainWriteProc)(lockp);
!         return;
!     }
! 
!     if (lockOrderValidation) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         if (lockp->level != 0) 
!             lock_VerifyOrderRW(lockRefH, lockRefT, lockp);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL) || 
!         (lockp->readers > 0)) {
!         lockp->waiters++;
!         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
!         lockp->waiters--;
!         osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
!     }
!     else {
!         /* if we're here, all clear to set the lock */
!         lockp->flags |= OSI_LOCKFLAG_EXCL;
!     }
! 
!     lockp->tid = thrd_Current();
! 
!     LeaveCriticalSection(csp);
! 
!     if (lockOrderValidation) {
!         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
!         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! }       
  
! void lock_ObtainRead(osi_rwlock_t *lockp)
! {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
!         
!     if ((i=lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ObtainReadProc)(lockp);
!         return;
!     }
! 
!     if (lockOrderValidation) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         if (lockp->level != 0) 
!             lock_VerifyOrderRW(lockRefH, lockRefT, lockp);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
!         lockp->waiters++;
!         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4READ, &lockp->readers, csp);
!         lockp->waiters--;
!         osi_assert(!(lockp->flags & OSI_LOCKFLAG_EXCL) && lockp->readers > 0);
!     }
!     else {
!         /* if we're here, all clear to set the lock */
!         lockp->readers++;
!     }
  
!     LeaveCriticalSection(csp);
  
!     if (lockOrderValidation) {
!         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
!         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
  }
  
! void lock_ReleaseRead(osi_rwlock_t *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
!         
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ReleaseReadProc)(lockp);
!         return;
!     }
! 
!     if (lockOrderValidation && lockp->level != 0) {
!         int found = 0;
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
!                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
!                 free(lockRefp);
!                 found = 1;
!                 break;
!             }
!         }
!         osi_assertx(found, "read lock not found in TLS queue");
! 
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(lockp->readers > 0, "read lock not held");
! 
!     /* releasing a read lock can allow readers or writers */
!     if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
!     }
!     else {
!         /* and finally release the big lock */
!         LeaveCriticalSection(csp);
!     }
! }
  
! void lock_ReleaseWrite(osi_rwlock_t *lockp)
! {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ReleaseWriteProc)(lockp);
!         return;
!     }
! 
!     if (lockOrderValidation && lockp->level != 0) {
!         int found = 0;
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
!                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
!                 free(lockRefp);
!                 found = 1;
!                 break;
!             }
!         }
!         osi_assertx(found, "write lock not found in TLS queue");
! 
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
!     osi_assertx(lockp->tid == thrd_Current(), "write lock not held by current thread");
! 
!     lockp->tid = 0;
! 
!     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!     if (!osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
!     }
!     else {
!         /* and finally release the big lock */
!         LeaveCriticalSection(csp);
!     }
! }       
  
! void lock_ConvertWToR(osi_rwlock_t *lockp)
! {
!     long i;
!     CRITICAL_SECTION *csp;
  
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ConvertWToRProc)(lockp);
!         return;
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "write lock not held");
!     osi_assertx(lockp->tid == thrd_Current(), "write lock not held by current thread");
! 
!     /* convert write lock to read lock */
!     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!     lockp->readers++;
! 
!     lockp->tid = 0;
! 
!     if (!osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, /* still have readers */ 1, csp);
!     }
!     else {
!         /* and finally release the big lock */
!         LeaveCriticalSection(csp);
!     }
  }
  
  void lock_ConvertRToW(osi_rwlock_t *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
  
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ConvertRToWProc)(lockp);
!         return;
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(!(lockp->flags & OSI_LOCKFLAG_EXCL), "write lock held");
!     osi_assertx(lockp->readers > 0, "read lock not held");
! 
!     if (--lockp->readers == 0) {
!         /* convert read lock to write lock */
!         lockp->flags |= OSI_LOCKFLAG_EXCL;
!     } else {
!         lockp->waiters++;
!         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
!         lockp->waiters--;
!         osi_assert(lockp->readers == 0 && (lockp->flags & OSI_LOCKFLAG_EXCL));
!     }
! 
!     lockp->tid = thrd_Current();
!     LeaveCriticalSection(csp);
! }       
  
  void lock_ObtainMutex(struct osi_mutex *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
!         
!     if ((i=lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ObtainMutexProc)(lockp);
!         return;
!     }
! 
!     if (lockOrderValidation) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         if (lockp->level != 0) 
!             lock_VerifyOrderMX(lockRefH, lockRefT, lockp);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
!         lockp->waiters++;
!         osi_TWait(&lockp->d.turn, OSI_SLEEPINFO_W4WRITE, &lockp->flags, csp);
!         lockp->waiters--;
!         osi_assert(lockp->flags & OSI_LOCKFLAG_EXCL);
!     }
!     else {
!         /* if we're here, all clear to set the lock */
!         lockp->flags |= OSI_LOCKFLAG_EXCL;
!     }
!     lockp->tid = thrd_Current();
!     LeaveCriticalSection(csp);
! 
!     if (lockOrderValidation) {
!         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_MUTEX);
!         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
  }
  
  void lock_ReleaseMutex(struct osi_mutex *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->ReleaseMutexProc)(lockp);
!         return;
!     }
! 
!     if (lockOrderValidation && lockp->level != 0) {
!         int found = 0;
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!             if (lockRefp->type == OSI_LOCK_MUTEX && lockRefp->mx == lockp) {
!                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
!                 free(lockRefp);
!                 found = 1;
!                 break;
!             }
!         }
!     
!         osi_assertx(found, "mutex lock not found in TLS queue");
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "mutex not held");
!     osi_assertx(lockp->tid == thrd_Current(), "mutex not held by current thread");
! 
!     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!     lockp->tid = 0;
!     if (!osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, 0, csp);
!     }
!     else {
!         /* and finally release the big lock */
!         LeaveCriticalSection(csp);
!     }
! }       
  
  int lock_TryRead(struct osi_rwlock *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i=lockp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             return (osi_lockOps[i]->TryReadProc)(lockp);
! 
!     if (lockOrderValidation) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         if (lockp->level != 0) {
!             for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!                 if (lockRefp->type == OSI_LOCK_RW) {
!                     osi_assertx(lockRefp->rw != lockp, "RW Lock already held");
!                 }
!             }
!         }
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
!         i = 0;
!     }
!     else {
!         /* if we're here, all clear to set the lock */
!         lockp->readers++;
!         i = 1;
!     }
  
!     LeaveCriticalSection(csp);
  
!     if (lockOrderValidation && i) {
!         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
!         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
  
!     return i;
! }       
  
  
  int lock_TryWrite(struct osi_rwlock *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i=lockp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             return (osi_lockOps[i]->TryWriteProc)(lockp);
! 
!     if (lockOrderValidation) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         if (lockp->level != 0) {
!             for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!                 if (lockRefp->type == OSI_LOCK_RW) {
!                     osi_assertx(lockRefp->rw != lockp, "RW Lock already held");
!                 }
!             }
!         }
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)
!          || (lockp->readers > 0)) {
!         i = 0;
!     }
!     else {
!         /* if we're here, all clear to set the lock */
!         lockp->flags |= OSI_LOCKFLAG_EXCL;
!         i = 1;
!     }
  
!     if (i)
!         lockp->tid = thrd_Current();
  
!     LeaveCriticalSection(csp);
  
!     if (lockOrderValidation && i) {
!         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_RW);
!         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
  
!     return i;
  }
  
  
  int lock_TryMutex(struct osi_mutex *lockp) {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i=lockp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             return (osi_lockOps[i]->TryMutexProc)(lockp);
! 
!     if (lockOrderValidation) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         if (lockp->level != 0) {
!             for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!                 if (lockRefp->type == OSI_LOCK_MUTEX) {
!                     osi_assertx(lockRefp->mx != lockp, "Mutex already held");
!                 }
!             }
!         }
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lockp->waiters > 0 || (lockp->flags & OSI_LOCKFLAG_EXCL)) {
!         i = 0;
!     }
!     else {
!         /* if we're here, all clear to set the lock */
!         lockp->flags |= OSI_LOCKFLAG_EXCL;
!         i = 1;
!     }
  
!     if (i)
!         lockp->tid = thrd_Current();
  
!     LeaveCriticalSection(csp);
  
!     if (lockOrderValidation && i) {
!         lockRefp = lock_GetLockRef(lockp, OSI_LOCK_MUTEX);
!         osi_QAddH(&lockRefH, &lockRefT, &lockRefp->q);
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
!     return i;
  }
  
  void osi_SleepR(LONG_PTR sleepVal, struct osi_rwlock *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->SleepRProc)(sleepVal, lockp);
!         return;
!     }
! 
!     if (lockOrderValidation && lockp->level != 0) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
!                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
!                 free(lockRefp);
!                 break;
!             }
!         }
! 
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(lockp->readers > 0, "osi_SleepR: not held");
! 
!     /* XXX better to get the list of things to wakeup from TSignalForMLs, and
!      * then do the wakeup after SleepSpin releases the low-level mutex.
!      */
!     if (--lockp->readers == 0 && !osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
!     }
! 
!     /* now call into scheduler to sleep atomically with releasing spin lock */
!     osi_SleepSpin(sleepVal, csp);
! }       
  
  void osi_SleepW(LONG_PTR sleepVal, struct osi_rwlock *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->SleepWProc)(sleepVal, lockp);
!         return;
!     }
! 
!     if (lockOrderValidation && lockp->level != 0) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!             if (lockRefp->type == OSI_LOCK_RW && lockRefp->rw == lockp) {
!                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
!                 free(lockRefp);
!                 break;
!             }
!         }
! 
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
! 
!     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepW: not held");
! 
!     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!     if (!osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
!     }
  
!     /* and finally release the big lock */
!     osi_SleepSpin(sleepVal, csp);
  }
  
  void osi_SleepM(LONG_PTR sleepVal, struct osi_mutex *lockp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
!     osi_queue_t * lockRefH, *lockRefT;
!     osi_lock_ref_t *lockRefp;
! 
!     if ((i = lockp->type) != 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->SleepMProc)(sleepVal, lockp);
!         return;
!     }
! 
!     if (lockOrderValidation && lockp->level != 0) {
!         lockRefH = (osi_queue_t *)TlsGetValue(tls_LockRefH);
!         lockRefT = (osi_queue_t *)TlsGetValue(tls_LockRefT);
! 
!         for (lockRefp = (osi_lock_ref_t *)lockRefH ; lockRefp; lockRefp = (osi_lock_ref_t *)osi_QNext(&lockRefp->q)) {
!             if (lockRefp->type == OSI_LOCK_MUTEX && lockRefp->mx == lockp) {
!                 osi_QRemoveHT(&lockRefH, &lockRefT, &lockRefp->q);
!                 free(lockRefp);
!                 break;
!             }
!         }
!     
!         TlsSetValue(tls_LockRefH, lockRefH);
!         TlsSetValue(tls_LockRefT, lockRefT);
!     }
! 
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lockp->atomicIndex];
!     EnterCriticalSection(csp);
  
!     osi_assertx(lockp->flags & OSI_LOCKFLAG_EXCL, "osi_SleepM not held");
  	
!     lockp->flags &= ~OSI_LOCKFLAG_EXCL;
!     if (!osi_TEmpty(&lockp->d.turn)) {
!         osi_TSignalForMLs(&lockp->d.turn, 0, NULL);
!     }
  
!     /* and finally release the big lock */
!     osi_SleepSpin(sleepVal, csp);
  }
  
  void lock_FinalizeRWLock(osi_rwlock_t *lockp)
  {
!     long i;
  
!     if ((i=lockp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->FinalizeRWLockProc)(lockp);
! }       
  
  void lock_FinalizeMutex(osi_mutex_t *lockp)
! {       
!     long i;
  
!     if ((i=lockp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->FinalizeMutexProc)(lockp);
! }       
! 
! void lock_InitializeMutex(osi_mutex_t *mp, char *namep, unsigned short level)
! {
!     int i;
! 
!     if ((i = osi_lockTypeDefault) > 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->InitializeMutexProc)(mp, namep, level);
!         return;
!     }
! 
!     /* otherwise we have the base case, which requires no special
!      * initialization.
!      */
!     mp->type = 0;
!     mp->flags = 0;
!     mp->tid = 0;
!     mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
!     mp->level = level;
!     osi_TInit(&mp->d.turn);
!     return;
! }
! 
! void lock_InitializeRWLock(osi_rwlock_t *mp, char *namep, unsigned short level)
! {
!     int i;
! 
!     if ((i = osi_lockTypeDefault) > 0) {
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             (osi_lockOps[i]->InitializeRWLockProc)(mp, namep, level);
!         return;
!     }
  	
!     /* otherwise we have the base case, which requires no special
!      * initialization.
!      */
!     mp->type = 0;
!     mp->flags = 0;
!     mp->atomicIndex = (unsigned short)(InterlockedIncrement(&atomicIndexCounter) % OSI_MUTEXHASHSIZE);
!     mp->readers = 0;
!     mp->tid = 0;
!     mp->level = level;
!     osi_TInit(&mp->d.turn);
!     return;
  }
  
  int lock_GetRWLockState(osi_rwlock_t *lp)
  {
!     long i;
!     CRITICAL_SECTION *csp;
  
!     if ((i=lp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             return (osi_lockOps[i]->GetRWLockState)(lp);
  
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[lp->atomicIndex];
!     EnterCriticalSection(csp);
  
!     /* here we have the fast lock, so see if we can obtain the real lock */
!     if (lp->flags & OSI_LOCKFLAG_EXCL) 
!         i = OSI_RWLOCK_WRITEHELD;
!     else 
!         i = 0;
!     if (lp->readers > 0) 
!         i |= OSI_RWLOCK_READHELD;
  
!     LeaveCriticalSection(csp);
  
!     return i;
  }
  
! int lock_GetMutexState(struct osi_mutex *mp) 
! {
!     long i;
!     CRITICAL_SECTION *csp;
  
!     if ((i=mp->type) != 0)
!         if (i >= 0 && i < OSI_NLOCKTYPES)
!             return (osi_lockOps[i]->GetMutexState)(mp);
  
!     /* otherwise we're the fast base type */
!     csp = &osi_baseAtomicCS[mp->atomicIndex];
!     EnterCriticalSection(csp);
  
!     if (mp->flags & OSI_LOCKFLAG_EXCL)
!         i = OSI_MUTEX_HELD;
!     else
!         i = 0;
  
!     LeaveCriticalSection(csp);
  
!     return i;
  }
Index: openafs/src/WINNT/client_osi/osibasel.h
diff -c openafs/src/WINNT/client_osi/osibasel.h:1.5.4.3 openafs/src/WINNT/client_osi/osibasel.h:1.5.4.4
*** openafs/src/WINNT/client_osi/osibasel.h:1.5.4.3	Wed Feb 27 12:06:44 2008
--- openafs/src/WINNT/client_osi/osibasel.h	Fri Aug 22 14:10:08 2008
***************
*** 28,43 ****
   * lock using an atomic increment operation.
   */
  typedef struct osi_mutex {
! 	char type;			/* for all types; type 0 uses atomic count */
! 	char flags;			/* flags for base type */
! 	unsigned short atomicIndex;	/* index of lock for low-level sync */
!         DWORD tid;			/* tid of thread that owns the lock */
! 	unsigned short waiters;		/* waiters */
!         unsigned short pad;
! 	union {
! 		void *privateDatap;	/* data pointer for non-zero types */
!                 osi_turnstile_t turn;	/* turnstile */
! 	} d;
  } osi_mutex_t;
  
  /* a read/write lock.  This structure has two forms.  In the
--- 28,44 ----
   * lock using an atomic increment operation.
   */
  typedef struct osi_mutex {
!     char type;			/* for all types; type 0 uses atomic count */
!     char flags;			/* flags for base type */
!     unsigned short atomicIndex;	/* index of lock for low-level sync */
!     DWORD tid;			/* tid of thread that owns the lock */
!     unsigned short waiters;	/* waiters */
!     unsigned short pad;
!     union {
!         void *privateDatap;	/* data pointer for non-zero types */
!         osi_turnstile_t turn;	/* turnstile */
!     } d;
!     unsigned short level;       /* locking hierarchy level */
  } osi_mutex_t;
  
  /* a read/write lock.  This structure has two forms.  In the
***************
*** 53,70 ****
   * This type of lock has N readers or one writer.
   */
  typedef struct osi_rwlock {
! 	char type;			/* for all types; type 0 uses atomic count */
! 	char flags;			/* flags for base type */
!         unsigned short atomicIndex;	/* index into hash table for low-level sync */
!         DWORD tid;			/* writer's tid */
!         unsigned short waiters;		/* waiters */
! 	unsigned short readers;		/* readers */
! 	union {
! 		void *privateDatap;	/* data pointer for non-zero types */
!                 osi_turnstile_t turn;	/* turnstile */
! 	} d;
  } osi_rwlock_t;
  
  extern void lock_ObtainRead (struct osi_rwlock *);
  
  extern void lock_ObtainWrite (struct osi_rwlock *);
--- 54,90 ----
   * This type of lock has N readers or one writer.
   */
  typedef struct osi_rwlock {
!     char type;			/* for all types; type 0 uses atomic count */
!     char flags;			/* flags for base type */
!     unsigned short atomicIndex;	/* index into hash table for low-level sync */
!     DWORD tid;			/* writer's tid */
!     unsigned short waiters;	/* waiters */
!     unsigned short readers;	/* readers */
!     union {
!         void *privateDatap;	/* data pointer for non-zero types */
!         osi_turnstile_t turn;	/* turnstile */
!     } d;
!     unsigned short level;       /* locking hierarchy level */
  } osi_rwlock_t;
  
+ 
+ /* 
+  * a lock reference is a queue object that maintains a reference to a 
+  * mutex or read/write lock object.  Its intended purpose is for 
+  * maintaining lists of lock objects on a per thread basis.
+  */
+ typedef struct osi_lock_ref {
+     osi_queue_t q;
+     char type;
+     union {
+         osi_rwlock_t *rw;
+         osi_mutex_t  *mx;
+     };
+ } osi_lock_ref_t;
+ 
+ #define OSI_LOCK_MUTEX  1
+ #define OSI_LOCK_RW     2
+ 
  extern void lock_ObtainRead (struct osi_rwlock *);
  
  extern void lock_ObtainWrite (struct osi_rwlock *);
***************
*** 101,109 ****
  
  /* and define the functions that create basic locks and mutexes */
  
! extern void lock_InitializeRWLock(struct osi_rwlock *, char *);
  
! extern void lock_InitializeMutex(struct osi_mutex *, char *);
  
  extern void osi_Init (void);
  
--- 121,129 ----
  
  /* and define the functions that create basic locks and mutexes */
  
! extern void lock_InitializeRWLock(struct osi_rwlock *, char *, unsigned short level);
  
! extern void lock_InitializeMutex(struct osi_mutex *, char *, unsigned short level);
  
  extern void osi_Init (void);
  
***************
*** 123,128 ****
--- 143,150 ----
  
  /* and friendly macros */
  
+ #define lock_AssertNone(x) osi_assertx(lock_GetRWLockState(x) == 0, "(OSI_RWLOCK_READHELD | OSI_RWLOCK_WRITEHELD)")
+ 
  #define lock_AssertRead(x) osi_assertx(lock_GetRWLockState(x) & OSI_RWLOCK_READHELD, "!OSI_RWLOCK_READHELD")
  
  #define lock_AssertWrite(x) osi_assertx(lock_GetRWLockState(x) & OSI_RWLOCK_WRITEHELD, "!OSI_RWLOCK_WRITEHELD")
Index: openafs/src/WINNT/client_osi/osifd.c
diff -c openafs/src/WINNT/client_osi/osifd.c:1.3 openafs/src/WINNT/client_osi/osifd.c:1.3.14.1
*** openafs/src/WINNT/client_osi/osifd.c:1.3	Sun Mar  9 20:59:15 2003
--- openafs/src/WINNT/client_osi/osifd.c	Fri Aug 22 14:10:08 2008
***************
*** 13,23 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <rpc.h>
  #include "dbrpc.h"
- #endif /* !DJGPP */
  #include <malloc.h>
  #include "osi.h"
  #include <assert.h>
--- 13,21 ----
***************
*** 29,37 ****
  
  osi_fdOps_t osi_TypeFDOps = {
  	osi_FDTypeCreate,
- #ifndef DJGPP
  	osi_FDTypeGetInfo,
- #endif
  	osi_FDTypeClose
  };
  
--- 27,33 ----
***************
*** 216,222 ****
  }
  
  
- #ifndef DJGPP
  long osi_FDTypeGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *outp)
  {
  	osi_typeFD_t *fdp;
--- 212,217 ----
***************
*** 239,245 ****
  		return OSI_DBRPC_EOF;
  	}
  }
- #endif /* !DJGPP */
  
  long osi_FDTypeClose(osi_fd_t *ifdp)
  {
--- 234,239 ----
Index: openafs/src/WINNT/client_osi/osilog.c
diff -c openafs/src/WINNT/client_osi/osilog.c:1.12.4.5 openafs/src/WINNT/client_osi/osilog.c:1.12.4.6
*** openafs/src/WINNT/client_osi/osilog.c:1.12.4.5	Fri Aug  1 00:23:56 2008
--- openafs/src/WINNT/client_osi/osilog.c	Fri Aug 22 14:10:08 2008
***************
*** 12,26 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
  #include <rpc.h>
- #endif /* !DJGPP */
  #include <malloc.h>
  #include "osi.h"
- #ifndef DJGPP
  #include "dbrpc.h"
- #endif /* !DJGPP */
  #include <stdio.h>
  #include <assert.h>
  #include <WINNT\afsreg.h>
--- 12,22 ----
***************
*** 48,56 ****
  
  osi_fdOps_t osi_logFDOps = {
  	osi_LogFDCreate,
- #ifndef DJGPP
          osi_LogFDGetInfo,
- #endif
          osi_LogFDClose
  };
  
--- 44,50 ----
***************
*** 64,70 ****
          LARGE_INTEGER bigTemp;
          LARGE_INTEGER bigJunk;
  	
- #ifndef DJGPP
  	if (osi_Once(&osi_logOnce)) {
  		QueryPerformanceFrequency(&bigFreq);
                  if (bigFreq.LowPart == 0 && bigFreq.HighPart == 0)
--- 58,63 ----
***************
*** 86,92 ****
  		/* done with init */
  		osi_EndOnce(&osi_logOnce);
          }
- #endif /* !DJGPP */
  
          logp = malloc(sizeof(osi_log_t));
          memset(logp, 0, sizeof(osi_log_t));
--- 79,84 ----
***************
*** 116,122 ****
  	StringCbCopyA(tbuffer, sizeof(tbuffer), "log:");
          StringCbCatA(tbuffer, sizeof(tbuffer), namep);
  	typep = osi_RegisterFDType(tbuffer, &osi_logFDOps, logp);
- #ifndef DJGPP
  	if (typep) {
  		/* add formatting info */
  		osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
--- 108,113 ----
***************
*** 124,138 ****
  		osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONSTRING, 1,
  			"Time (mics)", 0);
  	}
- #endif
  	
          return logp;
  }
  
! /* we just panic'd.  Turn off all logging adding special log record
!  * to all enabled logs.  Be careful not to wait for a lock.
   */
! void osi_LogPanic(char *filep, size_t lineNumber)
  {
  	osi_log_t *tlp;
  
--- 115,128 ----
  		osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONSTRING, 1,
  			"Time (mics)", 0);
  	}
  	
          return logp;
  }
  
! /* we just panic'd.  Log the error to all enabled log files.
!  * Be careful not to wait for a lock.
   */
! void osi_LogPanic(char *msgp, char *filep, size_t lineNumber)
  {
  	osi_log_t *tlp;
  
***************
*** 141,149 ****
  
  		/* otherwise, proceed */
  		if (filep)
! 	                osi_LogAdd(tlp, "**PANIC** (file %s:%d)", (size_t) filep, lineNumber, 0, 0, 0);
  		else
! 			osi_LogAdd(tlp, "**PANIC**", 0, 0, 0, 0, 0);
  		
                  /* should grab lock for this, but we're in panic, and better safe than
                   * sorry.
--- 131,139 ----
  
  		/* otherwise, proceed */
  		if (filep)
! 	                osi_LogAdd(tlp, "**PANIC** \"%s\" (file %s:%d)", (size_t) msgp, (size_t) filep, lineNumber, 0, 0);
  		else
! 			osi_LogAdd(tlp, "**PANIC** \"%s\"", (size_t)msgp, 0, 0, 0, 0);
  		
                  /* should grab lock for this, but we're in panic, and better safe than
                   * sorry.
***************
*** 203,217 ****
          lep->tid = thrd_Current();
  
  	/* get the time, using the high res timer if available */
- #ifndef DJGPP
          if (osi_logFreq) {
  		QueryPerformanceCounter(&bigTime);
  		lep->micros = (bigTime.LowPart / osi_logFreq) * osi_logTixToMicros;
          }
          else lep->micros = GetCurrentTime() * 1000;
- #else
-         lep->micros = gettime_us();
- #endif /* !DJGPP */                
  
          lep->formatp = formatp;
          lep->parms[0] = p0;
--- 193,203 ----
Index: openafs/src/WINNT/client_osi/osilog.h
diff -c openafs/src/WINNT/client_osi/osilog.h:1.7.4.3 openafs/src/WINNT/client_osi/osilog.h:1.7.4.4
*** openafs/src/WINNT/client_osi/osilog.h:1.7.4.3	Fri Aug  1 00:23:56 2008
--- openafs/src/WINNT/client_osi/osilog.h	Fri Aug 22 14:10:08 2008
***************
*** 75,81 ****
  
  extern void osi_LogDisable(osi_log_t *);
  
! extern void osi_LogPanic(char *filep, size_t line);
  
  extern void osi_LogPrint(osi_log_t *logp, FILE_HANDLE handle);
  
--- 75,81 ----
  
  extern void osi_LogDisable(osi_log_t *);
  
! extern void osi_LogPanic(char *msgp, char *filep, size_t line);
  
  extern void osi_LogPrint(osi_log_t *logp, FILE_HANDLE handle);
  
Index: openafs/src/WINNT/client_osi/osiltype.h
diff -c openafs/src/WINNT/client_osi/osiltype.h:1.2.4.1 openafs/src/WINNT/client_osi/osiltype.h:1.2.4.2
*** openafs/src/WINNT/client_osi/osiltype.h:1.2.4.1	Wed Feb 27 12:06:44 2008
--- openafs/src/WINNT/client_osi/osiltype.h	Fri Aug 22 14:10:08 2008
***************
*** 30,37 ****
  	void (*SleepRProc)(LONG_PTR, struct osi_rwlock *);
  	void (*SleepWProc)(LONG_PTR, struct osi_rwlock *);
  	void (*SleepMProc)(LONG_PTR, struct osi_mutex *);
! 	void (*InitializeMutexProc)(struct osi_mutex *, char *);
! 	void (*InitializeRWLockProc)(struct osi_rwlock *, char *);
  	void (*FinalizeMutexProc)(struct osi_mutex *);
  	void (*FinalizeRWLockProc)(struct osi_rwlock *);
          void (*ConvertWToRProc)(struct osi_rwlock *);
--- 30,37 ----
  	void (*SleepRProc)(LONG_PTR, struct osi_rwlock *);
  	void (*SleepWProc)(LONG_PTR, struct osi_rwlock *);
  	void (*SleepMProc)(LONG_PTR, struct osi_mutex *);
! 	void (*InitializeMutexProc)(struct osi_mutex *, char *, unsigned short);
! 	void (*InitializeRWLockProc)(struct osi_rwlock *, char *, unsigned short);
  	void (*FinalizeMutexProc)(struct osi_mutex *);
  	void (*FinalizeRWLockProc)(struct osi_rwlock *);
          void (*ConvertWToRProc)(struct osi_rwlock *);
Index: openafs/src/WINNT/client_osi/osiqueue.c
diff -c openafs/src/WINNT/client_osi/osiqueue.c:1.3.14.1 openafs/src/WINNT/client_osi/osiqueue.c:1.3.14.2
*** openafs/src/WINNT/client_osi/osiqueue.c:1.3.14.1	Thu Jun  1 11:39:55 2006
--- openafs/src/WINNT/client_osi/osiqueue.c	Fri Aug 22 14:10:08 2008
***************
*** 12,20 ****
  #include <afs/param.h>
  #include <afs/stds.h>
  
- #ifndef DJGPP
  #include <windows.h>
- #endif /* !DJGPP */
  #include "osi.h"
  #include <stdlib.h>
  
--- 12,18 ----
Index: openafs/src/WINNT/client_osi/osisleep.c
diff -c openafs/src/WINNT/client_osi/osisleep.c:1.5.4.1 openafs/src/WINNT/client_osi/osisleep.c:1.5.4.2
*** openafs/src/WINNT/client_osi/osisleep.c:1.5.4.1	Thu Jun  1 11:39:55 2006
--- openafs/src/WINNT/client_osi/osisleep.c	Fri Aug 22 14:10:08 2008
***************
*** 674,683 ****
  
  void osi_panic(char *msgp, char *filep, long line)
  {
! 	osi_LogPanic(filep, line);
  
! 	if (notifFunc)
!        		(*notifFunc)(msgp, filep, line);
  }
  
  /* get time in seconds since some relatively recent time */
--- 674,683 ----
  
  void osi_panic(char *msgp, char *filep, long line)
  {
!     if (notifFunc)
!         (*notifFunc)(msgp, filep, line);
  
!     osi_LogPanic(msgp, filep, line);
  }
  
  /* get time in seconds since some relatively recent time */
Index: openafs/src/afs/afs.h
diff -c openafs/src/afs/afs.h:1.85.2.8 openafs/src/afs/afs.h:1.85.2.10
*** openafs/src/afs/afs.h:1.85.2.8	Wed Apr 30 15:08:04 2008
--- openafs/src/afs/afs.h	Mon Sep 22 15:35:26 2008
***************
*** 121,126 ****
--- 121,130 ----
  #define	BOP_STORE	2	/* parm1 is chunk to store */
  #define	BOP_PATH	3	/* parm1 is path, parm2 is chunk to fetch */
  
+ #if defined(AFS_CACHE_BYPASS)
+ #define	BOP_FETCH_NOCACHE	4   /* parms are: vnode ptr, offset, segment ptr, addr, cred ptr */
+ #endif
+ 
  #define	B_DONTWAIT	1	/* On failure return; don't wait */
  
  /* protocol is: refCount is incremented by user to take block out of free pool.
***************
*** 570,575 ****
--- 574,616 ----
  #define VRevokeWait   0x1
  #define VPageCleaning 0x2	/* Solaris - Cache Trunc Daemon sez keep out */
  
+ #if defined(AFS_DISCON_ENV)
+ 
+ /* Dirty disconnected vcache flags. */
+ #define VDisconSetTime		0x00000001  	/* set time. */
+ #define VDisconSetMode		0x00000002	/* set mode. */
+ /* XXX: to be continued ? */
+ #define VDisconTrunc		0x00000020	/* truncate file. */
+ #define VDisconSetAttrMask	0x0000003F	/* Masks for setattr ops. */
+ #define VDisconWriteClose	0x00000400	/* Write op on file close. */
+ #define VDisconWriteFlush	0x00000800	/* Write op on normal fsync/flush. */
+ #define VDisconWriteOsiFlush	0x00001000	/* Write op on osi flush. */
+ 
+ #define VDisconShadowed		0x00002000	/* Shadowed dir. */
+ #define VDisconRemove		0x00004000	/* Remove vnop. */
+ #define VDisconCreate		0x00008000	/* Create vnop. */
+ #define VDisconRename		0x00010000	/* Rename vnop. */
+ #define VDisconRenameSameDir	0x00020000	/* Rename in same dir. */
+ 
+ /*... to be continued ...  */
+ #endif
+ 
+ #if defined(AFS_CACHE_BYPASS)
+ /* vcache (file) cachingStates bits */
+ #define FCSDesireBypass   0x1	/* This file should bypass the cache */
+ #define FCSBypass         0x2	/* This file is currently NOT being cached */
+ #define FCSManuallySet    0x4	/* The bypass flags were set, or reset, manually (via pioctl)
+  				 				   and should not be overridden by the file's name */
+ 
+ /* Flag values used by the Transition routines */
+ #define TRANSChangeDesiredBit		0x1	/* The Transition routine should set or 
+ 										 * reset the FCSDesireBypass bit */
+ #define TRANSVcacheIsLocked			0x2	/* The Transition routine does not need to
+ 										 * lock vcache (it's already locked) */
+ #define TRANSSetManualBit		0x4	/* The Transition routine should set FCSManuallySet so that
+ 									 * filename checking does not override pioctl requests */	
+ #endif /* AFS_CACHE_BYPASS */
+ 
  #define	CPSIZE	    2
  #if defined(AFS_XBSD_ENV) || defined(AFS_DARWIN_ENV)
  #define vrefCount   v->v_usecount
***************
*** 634,639 ****
--- 675,694 ----
  #endif
      struct vcache *hnext;	/* Hash next */
      struct afs_q vhashq;	/* Hashed per-volume list */
+ 
+ #if defined(AFS_DISCON_ENV)
+     /*! Next element in afs_DDirtyVCList. Lock it with afs_DDirtyVCListLock. */
+     struct vcache *ddirty_next;
+     /*! Disconnected flags for this vcache element. */
+     uint32_t ddirty_flags;
+     /*! Shadow vnode + unique keep the shadow dir location. */
+     afs_uint32 shVnode;
+     afs_uint32 shUnique;
+     /*! The old parent FID for renamed vnodes. */
+     afs_uint32 oldVnode;
+     afs_uint32 oldUnique;
+ #endif
+ 
      struct VenusFid fid;
      struct mstat {
  	afs_size_t Length;
***************
*** 705,710 ****
--- 760,776 ----
  				 * this file. */
      short flockCount;		/* count of flock readers, or -1 if writer */
      char mvstat;		/* 0->normal, 1->mt pt, 2->root. */
+ 
+ #if defined(AFS_CACHE_BYPASS)
+ 	char cachingStates;			/* Caching policies for this file */
+ 	afs_uint32 cachingTransitions;		/* # of times file has flopped between caching and not */
+ #if defined(AFS_LINUX24_ENV)
+ 	off_t next_seq_offset;	/* Next sequential offset (used by prefetch/readahead) */
+ #else
+ 	off_t next_seq_blk_offset; /* accounted in blocks for Solaris & IRIX */
+ #endif
+ #endif		
+ 	
      afs_uint32 states;		/* state bits */
  #if	defined(AFS_SUN5_ENV)
      afs_uint32 vstates;		/* vstate bits */
Index: openafs/src/afs/afs_analyze.c
diff -c openafs/src/afs/afs_analyze.c:1.22.14.8 openafs/src/afs/afs_analyze.c:1.22.14.9
*** openafs/src/afs/afs_analyze.c:1.22.14.8	Sat Jun 28 23:39:12 2008
--- openafs/src/afs/afs_analyze.c	Fri Aug 22 14:52:57 2008
***************
*** 14,20 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_analyze.c,v 1.22.14.8 2008/06/29 03:39:12 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
--- 14,20 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_analyze.c,v 1.22.14.9 2008/08/22 18:52:57 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
***************
*** 382,388 ****
  	return shouldRetry;	/* should retry */
      }
  
!     if (!aconn) {
  	if (!areq->volumeError) {
  	    if (aerrP)
  		(aerrP->err_Network)++;
--- 382,388 ----
  	return shouldRetry;	/* should retry */
      }
  
!     if (!aconn || !aconn->srvr) {
  	if (!areq->volumeError) {
  	    if (aerrP)
  		(aerrP->err_Network)++;
Index: openafs/src/afs/afs_bypasscache.c
diff -c /dev/null openafs/src/afs/afs_bypasscache.c:1.1.2.2
*** /dev/null	Fri Sep 26 04:30:52 2008
--- openafs/src/afs/afs_bypasscache.c	Mon Sep 22 15:35:26 2008
***************
*** 0 ****
--- 1,649 ----
+ /*
+  * COPYRIGHT  ©  2000
+  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+  * ALL RIGHTS RESERVED
+  * 
+  * Permission is granted to use, copy, create derivative works
+  * and redistribute this software and such derivative works
+  * for any purpose, so long as the name of The University of
+  * Michigan is not used in any advertising or publicity
+  * pertaining to the use of distribution of this software
+  * without specific, written prior authorization.  If the
+  * above copyright notice or any other identification of the
+  * University of Michigan is included in any copy of any
+  * portion of this software, then the disclaimer below must
+  * also be included.
+  * 
+  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY O 
+  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGES.
+  */
+  
+  /*
+  * Portions Copyright (c) 2008
+  * The Linux Box Corporation
+  * ALL RIGHTS RESERVED
+  *
+  * Permission is granted to use, copy, create derivative works
+  * and redistribute this software and such derivative works
+  * for any purpose, so long as the name of the Linux Box
+  * Corporation is not used in any advertising or publicity
+  * pertaining to the use or distribution of this software
+  * without specific, written prior authorization.  If the
+  * above copyright notice or any other identification of the
+  * Linux Box Corporation is included in any copy of any
+  * portion of this software, then the disclaimer below must
+  * also be included.
+  *
+  * This software is provided as is, without representation
+  * from the Linux Box Corporation as to its fitness for any
+  * purpose, and without warranty by the Linux Box Corporation
+  * of any kind, either express or implied, including
+  * without limitation the implied warranties of
+  * merchantability and fitness for a particular purpose.  The
+  * Linux Box Corporation shall not be liable for any damages, 
+  * including special, indirect, incidental, or consequential 
+  * damages, with respect to any claim arising out of or in 
+  * connection with the use of the software, even if it has been 
+  * or is hereafter advised of the possibility of such damages.
+  */
+ 
+ 
+ #include <afsconfig.h>
+ #include "afs/param.h"
+ 
+ #if defined(AFS_CACHE_BYPASS)
+ 
+ #include "afs/afs_bypasscache.h"
+ 
+ /*
+  * afs_bypasscache.c
+  *
+  */
+ #include "afs/sysincludes.h" /* Standard vendor system headers */
+ #include "afs/afsincludes.h" /* Afs-based standard headers */
+ #include "afs/afs_stats.h"   /* statistics */
+ #include "afs/nfsclient.h"  
+ #include "rx/rx_globals.h"
+ 
+ #if defined(AFS_LINUX26_ENV)
+ #define LockPage(pp) lock_page(pp)
+ #define UnlockPage(pp) unlock_page(pp)
+ #endif
+ #define AFS_KMAP_ATOMIC
+ 
+ #ifndef afs_min
+ #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
+ #endif
+ 
+ /* conditional GLOCK macros */
+ #define COND_GLOCK(var)	\
+ 	do { \
+ 		var = ISAFS_GLOCK(); \
+ 		if(!var) \
+ 			RX_AFS_GLOCK(); \
+ 	} while(0);
+ 	
+ #define COND_RE_GUNLOCK(var) \
+ 	do { \
+ 		if(var)	\
+ 			RX_AFS_GUNLOCK(); \
+ 	} while(0);
+ 
+ 
+ /* conditional GUNLOCK macros */
+ 
+ #define COND_GUNLOCK(var) \
+ 	do {	\
+ 		var = ISAFS_GLOCK(); \
+ 		if(var)	\
+ 			RX_AFS_GUNLOCK(); \
+ 	} while(0);
+ 
+ #define COND_RE_GLOCK(var) \
+ 	do { \
+ 		if(var)	\
+ 			RX_AFS_GLOCK();	\
+ 	} while(0);
+ 
+ 
+ int cache_bypass_strategy 	= 	NEVER_BYPASS_CACHE;
+ int cache_bypass_threshold  =  	AFS_CACHE_BYPASS_DISABLED; /* file size > threshold triggers bypass */
+ int cache_bypass_prefetch = 1;	/* Should we do prefetching ? */
+ 
+ extern afs_rwlock_t afs_xcbhash;
+ 
+ /*
+  * This is almost exactly like the PFlush() routine in afs_pioctl.c,
+  * but that routine is static.  We are about to change a file from
+  * normal caching to bypass it's caching.  Therefore, we want to
+  * free up any cache space in use by the file, and throw out any
+  * existing VM pages for the file.  We keep track of the number of
+  * times we go back and forth from caching to bypass.
+  */
+ void afs_TransitionToBypass(register struct vcache *avc, register struct AFS_UCRED *acred, int aflags)
+ {
+ 
+     afs_int32 code;
+     struct vrequest treq;
+     int setDesire = 0;
+     int setManual = 0;
+ 
+     if(!avc)
+ 	return;
+ 		
+     if(avc->states & FCSBypass)
+ 	osi_Panic("afs_TransitionToBypass: illegal transition to bypass--already FCSBypass\n");		
+ 		
+     if(aflags & TRANSChangeDesiredBit)
+ 	setDesire = 1;
+     if(aflags & TRANSSetManualBit)
+ 	setManual = 1;
+ 		
+ #ifdef AFS_BOZONLOCK_ENV
+     afs_BozonLock(&avc->pvnLock, avc);	/* Since afs_TryToSmush will do a pvn_vptrunc */
+ #else
+ 	AFS_GLOCK();	
+ #endif
+     ObtainWriteLock(&avc->lock, 925);
+ 	
+     /* If we never cached this, just change state */
+     if(setDesire && (!avc->cachingStates & FCSBypass)) {
+ 	avc->states |= FCSBypass;
+ 	goto done;
+     }
+ 	/* cg2v, try to store any chunks not written 20071204 */
+ 	if (avc->execsOrWriters > 0) { 
+ 		code = afs_InitReq(&treq, acred);
+ 		if(!code)
+ 			code = afs_StoreAllSegments(avc, &treq, AFS_SYNC | AFS_LASTSTORE); 
+ 	}
+ #if 0
+ 	/* also cg2v, don't dequeue the callback */
+     ObtainWriteLock(&afs_xcbhash, 956);	
+     afs_DequeueCallback(avc);
+ 	ReleaseWriteLock(&afs_xcbhash);
+ #endif	
+     avc->states &= ~(CStatd | CDirty);	/* next reference will re-stat cache entry */
+     /* now find the disk cache entries */
+     afs_TryToSmush(avc, acred, 1);
+     osi_dnlc_purgedp(avc);
+     if (avc->linkData && !(avc->states & CCore)) {
+ 	afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
+ 	avc->linkData = NULL;
+     }		
+ 	
+     avc->cachingStates |= FCSBypass;    /* Set the bypass flag */
+     if(setDesire)
+ 	avc->cachingStates |= FCSDesireBypass;
+     if(setManual)
+ 	avc->cachingStates |= FCSManuallySet;
+     avc->cachingTransitions++;
+ 
+ done:		
+     ReleaseWriteLock(&avc->lock);
+ #ifdef AFS_BOZONLOCK_ENV
+     afs_BozonUnlock(&avc->pvnLock, avc);
+ #else
+ 	AFS_GUNLOCK();
+ #endif
+ }
+ 
+ /*
+  * This is almost exactly like the PFlush() routine in afs_pioctl.c,
+  * but that routine is static.  We are about to change a file from
+  * bypassing caching to normal caching.  Therefore, we want to
+  * throw out any existing VM pages for the file.  We keep track of
+  * the number of times we go back and forth from caching to bypass.
+  */
+ void afs_TransitionToCaching(register struct vcache *avc, register struct AFS_UCRED *acred, int aflags)
+ {
+     int resetDesire = 0;
+     int setManual = 0;
+ 
+     if(!avc)
+ 	return;
+ 		
+     if(!avc->states & FCSBypass)
+ 	osi_Panic("afs_TransitionToCaching: illegal transition to caching--already caching\n");		
+ 		
+     if(aflags & TRANSChangeDesiredBit)
+ 	resetDesire = 1;
+     if(aflags & TRANSSetManualBit)
+ 	setManual = 1;
+ 
+ #ifdef AFS_BOZONLOCK_ENV
+     afs_BozonLock(&avc->pvnLock, avc);	/* Since afs_TryToSmush will do a pvn_vptrunc */
+ #else
+ 	AFS_GLOCK();	
+ #endif
+     ObtainWriteLock(&avc->lock, 926);
+ 	
+     /* Ok, we actually do need to flush */
+     ObtainWriteLock(&afs_xcbhash, 957);
+     afs_DequeueCallback(avc);
+     avc->states &= ~(CStatd | CDirty);	/* next reference will re-stat cache entry */
+     ReleaseWriteLock(&afs_xcbhash);
+     /* now find the disk cache entries */
+     afs_TryToSmush(avc, acred, 1);
+     osi_dnlc_purgedp(avc);
+     if (avc->linkData && !(avc->states & CCore)) {
+ 	afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
+ 	avc->linkData = NULL;
+     }
+ 		
+     avc->cachingStates &= ~(FCSBypass);    /* Reset the bypass flag */
+     if (resetDesire)
+ 	avc->cachingStates &= ~(FCSDesireBypass);
+     if (setManual)
+ 	avc->cachingStates |= FCSManuallySet;
+     avc->cachingTransitions++;
+ 
+     ReleaseWriteLock(&avc->lock);
+ #ifdef AFS_BOZONLOCK_ENV
+     afs_BozonUnlock(&avc->pvnLock, avc);
+ #else
+ 	AFS_GUNLOCK();
+ #endif
+ }
+ 
+ /* In the case where there's an error in afs_NoCacheFetchProc or
+  * afs_PrefetchNoCache, all of the pages they've been passed need
+  * to be unlocked.
+  */
+ #if defined(AFS_LINUX24_ENV)
+ #define unlock_pages(auio) \
+     do { \
+ 	struct iovec *ciov;	\
+ 	struct page *pp; \
+ 	afs_int32 iovmax; \
+ 	afs_int32 iovno = 0; \
+ 	ciov = auio->uio_iov; \
+ 	iovmax = auio->uio_iovcnt - 1;	\
+ 	pp = (struct page*) ciov->iov_base;	\
+ 	afs_warn("BYPASS: Unlocking pages...");	\
+ 	while(1) { \
+ 	    if(pp != NULL && PageLocked(pp)) \
+ 		UnlockPage(pp);	\
+ 	    iovno++; \
+ 	    if(iovno > iovmax) \
+ 		break; \
+ 	    ciov = (auio->uio_iov + iovno);	\
+ 	    pp = (struct page*) ciov->iov_base;	\
+ 	} \
+ 	afs_warn("Pages Unlocked.\n"); \
+     } while(0);
+ #else
+ #ifdef UKERNEL
+ #define unlock_pages(auio) \
+ 	 do { } while(0);
+ #else
+ #error AFS_CACHE_BYPASS not implemented on this platform
+ #endif
+ #endif
+ 
+ /* no-cache prefetch routine */
+ static afs_int32
+ afs_NoCacheFetchProc(register struct rx_call *acall, 
+                      register struct vcache *avc, 
+ 					 register uio_t *auio, 
+                      afs_int32 release_pages)
+ {
+     afs_int32 length;
+     afs_int32 code;
+     int tlen;
+     int moredata, iovno, iovoff, iovmax, clen, result, locked;
+     struct iovec *ciov;
+     struct page *pp;
+     char *address;
+ #ifdef AFS_KMAP_ATOMIC
+     char *page_buffer = osi_Alloc(PAGE_SIZE);
+ #else
+     char *page_buffer = NULL;
+ #endif
+ 
+     ciov = auio->uio_iov;
+     pp = (struct page*) ciov->iov_base;
+     iovmax = auio->uio_iovcnt - 1;
+     iovno = iovoff = result = 0;	
+     do {
+ 
+ 	COND_GUNLOCK(locked);
+ 	code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
+ 	COND_RE_GLOCK(locked);
+ 
+ 	if (code != sizeof(afs_int32)) {
+ 	    result = 0;
+ 	    afs_warn("Preread error. code: %d instead of %d\n",
+ 		code, sizeof(afs_int32));
+ 	    unlock_pages(auio);
+ 	    goto done;
+ 	} else
+ 	    length = ntohl(length);		
+ 					
+ 	/*
+ 	 * The fetch protocol is extended for the AFS/DFS translator
+ 	 * to allow multiple blocks of data, each with its own length,
+ 	 * to be returned. As long as the top bit is set, there are more
+ 	 * blocks expected.
+ 	 *
+ 	 * We do not do this for AFS file servers because they sometimes
+ 	 * return large negative numbers as the transfer size.
+ 	 */
+ 	if (avc->states & CForeign) {
+ 	    moredata = length & 0x80000000;
+ 	    length &= ~0x80000000;
+ 	} else {
+ 	    moredata = 0;
+ 	}
+ 				
+ 	while (length > 0) {
+ 
+ 	    clen = ciov->iov_len - iovoff; 
+ 	    tlen = afs_min(length, clen);
+ #ifdef AFS_LINUX24_ENV
+ #ifndef AFS_KMAP_ATOMIC
+ 	    if(pp)
+ 		address = kmap(pp);
+ 	    else { 
+ 		/* rx doesn't provide an interface to simply advance
+ 		   or consume n bytes.  for now, allocate a PAGE_SIZE 
+ 		   region of memory to receive bytes in the case that 
+ 		   there were holes in readpages */
+ 		if(page_buffer == NULL)
+ 		    page_buffer = osi_Alloc(PAGE_SIZE);
+ 		    address = page_buffer;
+ 		}
+ #else
+ 	    address = page_buffer;
+ #endif
+ #else
+ #ifndef UKERNEL
+ #error AFS_CACHE_BYPASS not implemented on this platform
+ #endif
+ #endif /* LINUX24 */
+ 	    COND_GUNLOCK(locked);
+ 	    code = rx_Read(acall, address, tlen);
+ 	    COND_RE_GLOCK(locked);
+ 		
+ 	    if (code < 0) {
+ 	        afs_warn("afs_NoCacheFetchProc: rx_Read error. Return code was %d\n", code);
+ 		result = 0;
+ 		unlock_pages(auio);
+ 		goto done;
+ 	    } else if (code == 0) {
+ 		result = 0;
+ 		afs_warn("afs_NoCacheFetchProc: rx_Read returned zero. Aborting.\n");
+ 		unlock_pages(auio);
+ 		goto done;
+ 	    }
+ 	    length -= code;
+ 	    tlen -= code;
+ 		
+ 	    if(tlen > 0) {
+ 		iovoff += code;
+ 		address += code;
+ 			
+ 	    } else {
+ #ifdef AFS_LINUX24_ENV
+ #ifdef AFS_KMAP_ATOMIC
+ 		if(pp) {
+ 		    address = kmap_atomic(pp, KM_USER0);
+ 		    memcpy(address, page_buffer, PAGE_SIZE);
+ 		    kunmap_atomic(address, KM_USER0);
+ 		}
+ #endif
+ #else
+ #ifndef UKERNEL
+ #error AFS_CACHE_BYPASS not implemented on this platform
+ #endif
+ #endif /* LINUX 24 */
+ 			/* we filled a page, conditionally release it */
+ 			if(release_pages && ciov->iov_base) {
+ 				/* this is appropriate when no caller intends to unlock
+ 				 * and release the page */
+ #ifdef AFS_LINUX24_ENV
+ 				SetPageUptodate(pp);
+ 				if(PageLocked(pp))
+ 					UnlockPage(pp);	
+ 				else
+ 					afs_warn("afs_NoCacheFetchProc: page not locked at iovno %d!\n", iovno);
+ 				
+ #ifndef AFS_KMAP_ATOMIC
+ 				kunmap(pp);		
+ #endif
+ #else
+ #ifndef UKERNEL
+ #error AFS_CACHE_BYPASS not implemented on this platform
+ #endif
+ #endif /* LINUX24 */
+ 			}
+ 			/* and carry uio_iov */
+ 			iovno++;
+ 			if(iovno > iovmax) goto done;
+ 			
+ 			ciov = (auio->uio_iov + iovno);
+ 			pp = (struct page*) ciov->iov_base;
+ 			iovoff = 0;
+ 	    }
+ 	}
+     } while (moredata);
+ 	
+ done:
+     if(page_buffer)
+     	osi_Free(page_buffer, PAGE_SIZE);
+     return result;
+ }
+ 
+ 
+ /* dispatch a no-cache read request */
+ afs_int32
+ afs_ReadNoCache(register struct vcache *avc, 
+ 				register struct nocache_read_request *bparms, 
+ 				struct AFS_UCRED *acred)
+ {
+     afs_int32 code;
+     afs_int32 bcnt;
+     struct brequest *breq;
+     struct vrequest *areq;
+ 		
+     /* the reciever will free this */
+     areq = osi_Alloc(sizeof(struct vrequest));
+ 	
+     if (avc && avc->vc_error) {
+ 		code = EIO;
+ 		afs_warn("afs_ReadNoCache VCache Error!\n");
+ 		goto cleanup;
+     }
+     if ((code = afs_InitReq(areq, acred))) {
+ 		afs_warn("afs_ReadNoCache afs_InitReq error!\n");
+ 		goto cleanup;
+     }
+ 
+     AFS_GLOCK();		
+     code = afs_VerifyVCache(avc, areq);
+     AFS_GUNLOCK();
+ 	
+     if (code) {
+ 		code = afs_CheckCode(code, areq, 11);	/* failed to get it */
+ 		afs_warn("afs_ReadNoCache Failed to verify VCache!\n");
+ 		goto cleanup;
+     }
+ 	
+     bparms->areq = areq;
+ 	
+     /* and queue this one */
+     bcnt = 1;
+     AFS_GLOCK();
+     while(bcnt < 20) {
+     	breq = afs_BQueue(BOP_FETCH_NOCACHE, avc, B_DONTWAIT, 0, acred, 1, 1, bparms);
+ 		if(breq != 0) {
+ 			code = 0;
+ 			break;
+ 		}	
+ 		afs_osi_Wait(10 * bcnt, 0, 0);
+     }
+     AFS_GUNLOCK();
+     
+     if(!breq) {
+     	code = EBUSY;
+ 		goto cleanup;
+     }
+ 
+     return code;
+ 
+ cleanup:
+     /* If there's a problem before we queue the request, we need to
+      * do everything that would normally happen when the request was
+      * processed, like unlocking the pages and freeing memory.
+      */
+ #ifdef AFS_LINUX24_ENV
+     unlock_pages(bparms->auio);
+ #else
+ #ifndef UKERNEL
+ #error AFS_CACHE_BYPASS not implemented on this platform
+ #endif
+ #endif
+     osi_Free(areq, sizeof(struct vrequest));
+     osi_Free(bparms->auio->uio_iov, bparms->auio->uio_iovcnt * sizeof(struct iovec));	
+     osi_Free(bparms->auio, sizeof(uio_t));
+     osi_Free(bparms, sizeof(struct nocache_read_request));
+     return code;
+ 
+ }
+ 
+ 
+ /* Cannot have static linkage--called from BPrefetch (afs_daemons) */
+ afs_int32
+ afs_PrefetchNoCache(register struct vcache *avc, 
+ 					register struct AFS_UCRED *acred,
+ 					register struct nocache_read_request *bparms)
+ {
+     uio_t *auio;
+     struct iovec *iovecp;
+     struct vrequest *areq;
+     afs_int32 code, length_hi, bytes, locked;    
+ 	
+     register struct conn *tc;
+     afs_int32 i;
+     struct rx_call *tcall;
+     struct tlocal1 {
+ 		struct AFSVolSync tsync;
+ 		struct AFSFetchStatus OutStatus;
+ 		struct AFSCallBack CallBack;
+     };
+     struct tlocal1 *tcallspec;	
+ 			
+     auio = bparms->auio;
+     areq = bparms->areq;
+     iovecp = auio->uio_iov;	
+ 	
+     tcallspec = (struct tlocal1 *) osi_Alloc(sizeof(struct tlocal1));
+     do {
+ 		tc = afs_Conn(&avc->fid, areq, SHARED_LOCK /* ignored */);
+ 		if (tc) {
+ 			avc->callback = tc->srvr->server;
+ 			i = osi_Time();
+ 			tcall = rx_NewCall(tc->id);
+ #ifdef AFS_64BIT_CLIENT
+ 			if(!afs_serverHasNo64Bit(tc)) {
+ 				code = StartRXAFS_FetchData64(tcall,
+ 											  (struct AFSFid *) &avc->fid.Fid,
+ 											  auio->uio_offset, 
+ 											  bparms->length);
+ 				if (code == 0) {
+ 					
+ 					COND_GUNLOCK(locked);
+ 					bytes = rx_Read(tcall, (char *)&length_hi, sizeof(afs_int32));
+ 					COND_RE_GLOCK(locked);
+ 					
+ 					if (bytes != sizeof(afs_int32)) {
+ 						length_hi = 0;
+ 						code = rx_Error(tcall);
+ 						COND_GUNLOCK(locked);
+ 						code = rx_EndCall(tcall, code);
+ 						COND_RE_GLOCK(locked);
+ 						tcall = (struct rx_call *)0;
+ 					}
+ 				}					      
+ 				if (code == RXGEN_OPCODE || afs_serverHasNo64Bit(tc)) {
+ 					if (auio->uio_offset > 0x7FFFFFFF) {
+ 						code = EFBIG;
+ 					} else {
+ 						afs_int32 pos;
+ 						pos = auio->uio_offset;
+ 						COND_GUNLOCK(locked);
+ 						if (!tcall)
+ 							tcall = rx_NewCall(tc->id);						
+ 						code = StartRXAFS_FetchData(tcall,
+ 													(struct AFSFid *) &avc->fid.Fid,
+ 													pos, bparms->length);
+ 						COND_RE_GLOCK(locked);
+ 					}
+ 					afs_serverSetNo64Bit(tc);
+ 				}
+ 			} /* afs_serverHasNo64Bit */
+ #else
+ 			code = StartRXAFS_FetchData(tcall,
+ 										(struct AFSFid *) &avc->fid.Fid,
+ 										auio->uio_offset, bparms->length);
+ #endif
+ 
+ 			if (code == 0) {
+ 				code = afs_NoCacheFetchProc(tcall, avc, auio, 
+ 											1 /* release_pages */);
+ 			} else {
+ 				afs_warn("BYPASS: StartRXAFS_FetchData failed: %d\n", code);
+ 				unlock_pages(auio);
+ 				goto done;
+ 			}
+ 			if (code == 0) {
+ 				code = EndRXAFS_FetchData(tcall,
+ 										  &tcallspec->OutStatus,
+ 										  &tcallspec->CallBack,
+ 										  &tcallspec->tsync);
+ 			} else {
+ 				afs_warn("BYPASS: NoCacheFetchProc failed: %d\n", code);
+ 			}
+ 			code = rx_EndCall(tcall, code);
+ 		}
+ 		else {
+ 			afs_warn("BYPASS: No connection.\n");
+ 			code = -1;
+ #ifdef AFS_LINUX24_ENV
+ 			unlock_pages(auio);
+ #else
+ #ifndef UKERNEL
+ #error AFS_CACHE_BYPASS not implemented on this platform
+ #endif
+ #endif
+ 			goto done;
+ 		}
+     } while (afs_Analyze(tc, code, &avc->fid, areq,
+ 						 AFS_STATS_FS_RPCIDX_FETCHDATA,
+ 						 SHARED_LOCK,0));
+ done:
+     /*
+      * Copy appropriate fields into vcache
+      */
+ 
+     afs_ProcessFS(avc, &tcallspec->OutStatus, areq);
+ 
+     osi_Free(areq, sizeof(struct vrequest));
+     osi_Free(tcallspec, sizeof(struct tlocal1));
+     osi_Free(iovecp, auio->uio_iovcnt * sizeof(struct iovec));	
+     osi_Free(bparms, sizeof(struct nocache_read_request));
+     osi_Free(auio, sizeof(uio_t));
+     return code;
+ }
+ 
+ #endif /* AFS_CACHE_BYPASS */
Index: openafs/src/afs/afs_bypasscache.h
diff -c /dev/null openafs/src/afs/afs_bypasscache.h:1.1.2.2
*** /dev/null	Fri Sep 26 04:30:52 2008
--- openafs/src/afs/afs_bypasscache.h	Mon Sep 22 15:35:26 2008
***************
*** 0 ****
--- 1,153 ----
+ /*
+  * COPYRIGHT  ©  2000
+  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+  * ALL RIGHTS RESERVED
+  * 
+  * Permission is granted to use, copy, create derivative works
+  * and redistribute this software and such derivative works
+  * for any purpose, so long as the name of The University of
+  * Michigan is not used in any advertising or publicity
+  * pertaining to the use of distribution of this software
+  * without specific, written prior authorization.  If the
+  * above copyright notice or any other identification of the
+  * University of Michigan is included in any copy of any
+  * portion of this software, then the disclaimer below must
+  * also be included.
+  * 
+  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY O 
+  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGES.
+  */
+  
+  /*
+  * Portions Copyright (c) 2008
+  * The Linux Box Corporation
+  * ALL RIGHTS RESERVED
+  *
+  * Permission is granted to use, copy, create derivative works
+  * and redistribute this software and such derivative works
+  * for any purpose, so long as the name of the Linux Box
+  * Corporation is not used in any advertising or publicity
+  * pertaining to the use or distribution of this software
+  * without specific, written prior authorization.  If the
+  * above copyright notice or any other identification of the
+  * Linux Box Corporation is included in any copy of any
+  * portion of this software, then the disclaimer below must
+  * also be included.
+  *
+  * This software is provided as is, without representation
+  * from the Linux Box Corporation as to its fitness for any
+  * purpose, and without warranty by the Linux Box Corporation
+  * of any kind, either express or implied, including
+  * without limitation the implied warranties of
+  * merchantability and fitness for a particular purpose.  The
+  * Linux Box Corporation shall not be liable for any damages, 
+  * including special, indirect, incidental, or consequential 
+  * damages, with respect to any claim arising out of or in 
+  * connection with the use of the software, even if it has been 
+  * or is hereafter advised of the possibility of such damages.
+  */
+ 
+ 
+ #ifndef _AFS_BYPASSCACHE_H
+ #define _AFS_BYPASSCACHE_H
+ 
+ #if defined(AFS_CACHE_BYPASS)
+ 
+ #include <afsconfig.h>
+ #include "afs/param.h"
+ #include "afs/sysincludes.h"
+ #include "afsincludes.h"
+ 
+ #define AFS_CACHE_BYPASS_DISABLED -1
+ 
+ #ifdef UKERNEL
+ typedef struct uio uio_t;
+ #ifndef PAGE_SIZE
+ #define PAGE_SIZE 1024 * sizeof(long) / 8
+ #endif
+ #endif
+ 
+ /* A ptr to an object of the following type is expected to be passed
+  * as the ab->parm[0] to afs_BQueue */
+ struct nocache_read_request {
+     /* Why can't we all get along? */
+ #if defined(AFS_SUN5_ENV)
+     /* SOLARIS */
+     u_offset_t offset;
+     struct seg *segment;
+     caddr_t address;
+ #elif defined(AFS_SGI_ENV)
+     /* SGI (of some vintage) */
+     int32 offset;
+     int32 rem;
+     int32 pmp; /* mmm */
+     int32 length;
+ #elif defined(AFS_LINUX24_ENV) || defined(AFS_USR_LINUX24_ENV)
+     /* The tested platform, as CITI impl. just packs ab->parms */
+     uio_t * auio;
+     struct vrequest *areq;
+     afs_size_t offset;
+     afs_size_t length;
+ #endif
+ };
+ 
+ enum cache_bypass_strategies
+ {
+     ALWAYS_BYPASS_CACHE,
+     NEVER_BYPASS_CACHE,
+     LARGE_FILES_BYPASS_CACHE
+ };
+ 
+ extern int cache_bypass_prefetch;
+ extern int cache_bypass_strategy;
+ extern int cache_bypass_threshold;
+ 
+ void afs_TransitionToBypass(register struct vcache *, register struct AFS_UCRED *, int);
+ void afs_TransitionToCaching(register struct vcache *, register struct AFS_UCRED *, int);
+ 
+ /* Cache strategy permits vnode transition between caching and no-cache--
+  * currently, this means LARGE_FILES_BYPASS_CACHE.  Currently, no pioctl permits
+  * setting FCSBypass manually for a vnode */
+ #define variable_cache_strategy					\
+     (! ((cache_bypass_strategy == ALWAYS_BYPASS_CACHE) ||	\
+ 	(cache_bypass_strategy == NEVER_BYPASS_CACHE)) )
+ 
+ /* Cache-coherently toggle cache/no-cache for a vnode */
+ #define trydo_cache_transition(avc, credp, bypasscache)			\
+     do {								\
+ 	if(variable_cache_strategy) {					\
+ 	    if(bypasscache) {						\
+ 		if(!(avc->cachingStates & FCSBypass))			\
+ 		    afs_TransitionToBypass(avc, credp, TRANSChangeDesiredBit); \
+ 	    } else {							\
+ 		if(avc->cachingStates & FCSBypass)			\
+ 		    afs_TransitionToCaching(avc, credp, TRANSChangeDesiredBit);	\
+ 	    }								\
+ 	}								\
+     }									\
+     while(0);
+ 
+ /* dispatch a no-cache read request */
+ afs_int32
+ afs_ReadNoCache(register struct vcache *avc, register struct nocache_read_request *bparms, 
+ 		struct AFS_UCRED *acred);
+ 
+ /* no-cache prefetch routine */
+ afs_int32
+ afs_PrefetchNoCache(register struct vcache *avc, register struct AFS_UCRED *acred,
+ 			struct nocache_read_request *bparms);
+ 
+ 
+ #endif /* AFS_CACHE_BYPASS */
+ #endif /* _AFS_BYPASSCACHE_H */
+ 
Index: openafs/src/afs/afs_callback.c
diff -c openafs/src/afs/afs_callback.c:1.39.2.4 openafs/src/afs/afs_callback.c:1.39.2.5
*** openafs/src/afs/afs_callback.c:1.39.2.4	Mon Mar 10 18:32:32 2008
--- openafs/src/afs/afs_callback.c	Mon Sep 22 15:29:53 2008
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_callback.c,v 1.39.2.4 2008/03/10 22:32:32 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 17,23 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_callback.c,v 1.39.2.5 2008/09/22 19:29:53 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 66,71 ****
--- 66,75 ----
      { "afsdb_client_lock", (char *)&afsdb_client_lock},
      { "afsdb_req_lock", (char *)&afsdb_req_lock},
  #endif
+ #ifdef AFS_DISCON_ENV
+     { "afs_discon_lock", (char *)&afs_discon_lock},
+     { "afs_DDirtyVCListLock", (char *)&afs_DDirtyVCListLock},
+ #endif
  };
  unsigned long lastCallBack_vnode;
  unsigned int lastCallBack_dv;
Index: openafs/src/afs/afs_conn.c
diff -c openafs/src/afs/afs_conn.c:1.14.8.3 openafs/src/afs/afs_conn.c:1.14.8.4
*** openafs/src/afs/afs_conn.c:1.14.8.3	Fri May 23 10:25:15 2008
--- openafs/src/afs/afs_conn.c	Mon Sep 22 15:29:54 2008
***************
*** 14,20 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_conn.c,v 1.14.8.3 2008/05/23 14:25:15 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
--- 14,20 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_conn.c,v 1.14.8.4 2008/09/22 19:29:54 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
***************
*** 159,165 ****
  	return NULL;
      }
      
!     if (AFS_IS_DISCONNECTED) {
          afs_warnuser("afs_ConnBySA: disconnected\n");
          ReleaseSharedLock(&afs_xconn);
          return NULL;
--- 159,165 ----
  	return NULL;
      }
      
!     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
          afs_warnuser("afs_ConnBySA: disconnected\n");
          ReleaseSharedLock(&afs_xconn);
          return NULL;
***************
*** 276,282 ****
  
      AFS_STATCNT(afs_ConnByHost);
  
!     if (AFS_IS_DISCONNECTED) {
          afs_warnuser("afs_ConnByHost: disconnected\n");
          return NULL;
      }
--- 276,282 ----
  
      AFS_STATCNT(afs_ConnByHost);
  
!     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
          afs_warnuser("afs_ConnByHost: disconnected\n");
          return NULL;
      }
Index: openafs/src/afs/afs_daemons.c
diff -c openafs/src/afs/afs_daemons.c:1.43.2.5 openafs/src/afs/afs_daemons.c:1.43.2.6
*** openafs/src/afs/afs_daemons.c:1.43.2.5	Fri May 23 10:25:15 2008
--- openafs/src/afs/afs_daemons.c	Mon Sep 22 15:35:26 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_daemons.c,v 1.43.2.5 2008/05/23 14:25:15 shadow Exp $");
  
  #ifdef AFS_AIX51_ENV
  #define __FULL_PROTO
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_daemons.c,v 1.43.2.6 2008/09/22 19:35:26 shadow Exp $");
  
  #ifdef AFS_AIX51_ENV
  #define __FULL_PROTO
***************
*** 26,32 ****
  #include <sys/adspace.h>	/* for vm_att(), vm_det() */
  #endif
  
! 
  /* background request queue size */
  afs_lock_t afs_xbrs;		/* lock for brs */
  static int brsInit = 0;
--- 26,34 ----
  #include <sys/adspace.h>	/* for vm_att(), vm_det() */
  #endif
  
! #if defined(AFS_CACHE_BYPASS)
! #include "afs/afs_bypasscache.h"
! #endif// defined(AFS_CACHE_BYPASS)
  /* background request queue size */
  afs_lock_t afs_xbrs;		/* lock for brs */
  static int brsInit = 0;
***************
*** 516,521 ****
--- 518,544 ----
      }
  }
  
+ #if defined(AFS_CACHE_BYPASS)
+ #if 1 /* XXX Matt debugging */
+ static
+ #endif
+ void
+ BPrefetchNoCache(register struct brequest *ab)
+ {
+     struct vrequest treq;
+     afs_size_t len;
+ 	
+     if ((len = afs_InitReq(&treq, ab->cred)))
+ 	return;
+ 
+ #ifndef UKERNEL
+     /* OS-specific prefetch routine */
+     afs_PrefetchNoCache(ab->vc, ab->cred, (struct nocache_read_request *) ab->ptr_parm[0]);
+ #else
+ #warning Cache-bypass code path not implemented in UKERNEL
+ #endif
+ }
+ #endif
  
  static void
  BStore(register struct brequest *ab)
***************
*** 979,984 ****
--- 1002,1011 ----
  		       tb->opcode);
  	    if (tb->opcode == BOP_FETCH)
  		BPrefetch(tb);
+ #if defined(AFS_CACHE_BYPASS)		
+ 		else if (tb->opcode == BOP_FETCH_NOCACHE)
+ 		BPrefetchNoCache(tb);
+ #endif		
  	    else if (tb->opcode == BOP_STORE)
  		BStore(tb);
  	    else if (tb->opcode == BOP_PATH)
Index: openafs/src/afs/afs_dcache.c
diff -c openafs/src/afs/afs_dcache.c:1.64.4.8 openafs/src/afs/afs_dcache.c:1.64.4.11
*** openafs/src/afs/afs_dcache.c:1.64.4.8	Fri May 23 10:25:15 2008
--- openafs/src/afs/afs_dcache.c	Mon Sep 22 15:35:26 2008
***************
*** 14,20 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_dcache.c,v 1.64.4.8 2008/05/23 14:25:15 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 14,20 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_dcache.c,v 1.64.4.11 2008/09/22 19:35:26 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 34,40 ****
  static void afs_DCSizeInit(void);
  static afs_int32 afs_DCWhichBucket(afs_int32, afs_int32);
  
- 
  /*
   * --------------------- Exported definitions ---------------------
   */
--- 34,39 ----
***************
*** 462,468 ****
  	adc->validPos = 0;
      newSize = ((newSize + afs_fsfragsize) ^ afs_fsfragsize) >> 10;	/* round up */
      afs_DCAdjustSize(adc, oldSize, newSize);
!     if (newSize > oldSize) {
  	/* We're growing the file, wakeup the daemon */
  	afs_MaybeWakeupTruncateDaemon();
      }
--- 461,468 ----
  	adc->validPos = 0;
      newSize = ((newSize + afs_fsfragsize) ^ afs_fsfragsize) >> 10;	/* round up */
      afs_DCAdjustSize(adc, oldSize, newSize);
!     if ((newSize > oldSize) && !AFS_IS_DISCONNECTED) {
! 
  	/* We're growing the file, wakeup the daemon */
  	afs_MaybeWakeupTruncateDaemon();
      }
***************
*** 515,522 ****
--- 515,528 ----
      afs_uint32 maxVictimPtr;	/* where it is */
      int discard;
      int curbucket;
+     int vfslocked;
+ 
+ #if defined(AFS_FBSD80_ENV) && !defined(UKERNEL)
+     vfslocked = VFS_LOCK_GIANT(afs_globalVFS);
+ #endif
  
      AFS_STATCNT(afs_GetDownD);
+ 
      if (CheckLock(&afs_xdcache) != -1)
  	osi_Panic("getdownd nolock");
      /* decrement anumber first for all dudes in free list */
***************
*** 524,532 ****
       * because we should try to free space even if anumber <=0 */
      if (!aneedSpace || *aneedSpace <= 0) {
  	anumber -= afs_freeDCCount;
! 	if (anumber <= 0)
  	    return;		/* enough already free */
      }
      /* bounds check parameter */
      if (anumber > MAXATONCE)
  	anumber = MAXATONCE;	/* all we can do */
--- 530,543 ----
       * because we should try to free space even if anumber <=0 */
      if (!aneedSpace || *aneedSpace <= 0) {
  	anumber -= afs_freeDCCount;
! 	if (anumber <= 0) {
! #if defined(AFS_FBSD80_ENV) && !defined(UKERNEL)
! 	  VFS_UNLOCK_GIANT(vfslocked);
! #endif
  	    return;		/* enough already free */
+ 	}
      }
+ 
      /* bounds check parameter */
      if (anumber > MAXATONCE)
  	anumber = MAXATONCE;	/* all we can do */
***************
*** 763,769 ****
  			       ICL_TYPE_INT32, tdc->index, ICL_TYPE_OFFSET,
  			       ICL_HANDLE_OFFSET(tchunkoffset));
  		    AFS_STATCNT(afs_gget);
! 		    afs_HashOutDCache(tdc);
  		    if (tdc->f.chunkBytes != 0) {
  			discard = 1;
  			if (aneedSpace)
--- 774,780 ----
  			       ICL_TYPE_INT32, tdc->index, ICL_TYPE_OFFSET,
  			       ICL_HANDLE_OFFSET(tchunkoffset));
  		    AFS_STATCNT(afs_gget);
! 		    afs_HashOutDCache(tdc, 1);
  		    if (tdc->f.chunkBytes != 0) {
  			discard = 1;
  			if (aneedSpace)
***************
*** 799,804 ****
--- 810,820 ----
  		break;
  	}
      }				/* big while loop */
+ 
+ #if defined(AFS_FBSD80_ENV) && !defined(UKERNEL)
+     VFS_UNLOCK_GIANT(vfslocked);
+ #endif
+ 
      return;
  
  }				/*afs_GetDownD */
***************
*** 809,825 ****
   * again by afs_FindDCache or afs_GetDCache.
   *
   * Parameters: adc -- pointer to dcache entry to remove from hash tables.
   *
   * Locks: Must have the afs_xdcache lock write-locked to call this function.
   */
  int
! afs_HashOutDCache(struct dcache *adc)
  {
      int i, us;
  
      AFS_STATCNT(afs_glink);
!     /* we know this guy's in the LRUQ.  We'll move dude into DCQ below */
!     DZap(adc);
      /* if this guy is in the hash table, pull him out */
      if (adc->f.fid.Fid.Volume != 0) {
  	/* remove entry from first hash chains */
--- 825,843 ----
   * again by afs_FindDCache or afs_GetDCache.
   *
   * Parameters: adc -- pointer to dcache entry to remove from hash tables.
+  *	       zap -- zap the given dcache ?
   *
   * Locks: Must have the afs_xdcache lock write-locked to call this function.
   */
  int
! afs_HashOutDCache(struct dcache *adc, int zap)
  {
      int i, us;
  
      AFS_STATCNT(afs_glink);
!     if (zap)
! 	/* we know this guy's in the LRUQ.  We'll move dude into DCQ below */
! 	DZap(adc);
      /* if this guy is in the hash table, pull him out */
      if (adc->f.fid.Fid.Volume != 0) {
  	/* remove entry from first hash chains */
***************
*** 862,881 ****
  	}
      }
  
!     /* prevent entry from being found on a reboot (it is already out of
!      * the hash table, but after a crash, we just look at fid fields of
!      * stable (old) entries).
!      */
!     adc->f.fid.Fid.Volume = 0;	/* invalid */
  
!     /* mark entry as modified */
!     adc->dflags |= DFEntryMod;
  
      /* all done */
      return 0;
  }				/*afs_HashOutDCache */
  
- 
  /*
   * afs_FlushDCache
   *
--- 880,900 ----
  	}
      }
  
!     if (zap) {
!     	/* prevent entry from being found on a reboot (it is already out of
!      	 * the hash table, but after a crash, we just look at fid fields of
!      	 * stable (old) entries).
!      	 */
!     	 adc->f.fid.Fid.Volume = 0;	/* invalid */
  
!     	/* mark entry as modified */
!     	adc->dflags |= DFEntryMod;
!     }
  
      /* all done */
      return 0;
  }				/*afs_HashOutDCache */
  
  /*
   * afs_FlushDCache
   *
***************
*** 901,907 ****
      afs_stats_cmperf.cacheFlushes++;
  
      /* remove from all hash tables */
!     afs_HashOutDCache(adc);
  
      /* Free its space; special case null operation, since truncate operation
       * in UFS is slow even in this case, and this allows us to pre-truncate
--- 920,926 ----
      afs_stats_cmperf.cacheFlushes++;
  
      /* remove from all hash tables */
!     afs_HashOutDCache(adc, 1);
  
      /* Free its space; special case null operation, since truncate operation
       * in UFS is slow even in this case, and this allows us to pre-truncate
***************
*** 1320,1337 ****
  afs_DCacheMissingChunks(struct vcache *avc)
  {
      int i, index;
!     afs_size_t totalLength;
!     afs_uint32 totalChunks;
      struct dcache *tdc;
  
      totalLength = avc->m.Length;
      if (avc->truncPos < totalLength)
          totalLength = avc->truncPos;
  
!     totalChunks = AFS_CHUNK(totalLength) + 1;
  
!     /*printf("Should have %d chunks for %d bytes\n", totalChunks, totalLength);*/
!     
      i = DVHash(&avc->fid);
      MObtainWriteLock(&afs_xdcache, 1001);
      for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
--- 1339,1367 ----
  afs_DCacheMissingChunks(struct vcache *avc)
  {
      int i, index;
!     afs_size_t totalLength = 0;
!     afs_uint32 totalChunks = 0;
      struct dcache *tdc;
  
      totalLength = avc->m.Length;
      if (avc->truncPos < totalLength)
          totalLength = avc->truncPos;
  
!     /* Length is 0, no chunk missing. */
!     if (totalLength == 0)
!     	return 0;
  
!     /* If totalLength is a multiple of chunksize, the last byte appears
!      * as being part of the next chunk, which does not exist.
!      * Decrementing totalLength by one fixes that.
!      */
!     totalLength--;
!     totalChunks = (AFS_CHUNK(totalLength) + 1);
! 
!     /*
!      printf("Should have %d chunks for %u bytes\n",
!     		totalChunks, (totalLength + 1));
!     */
      i = DVHash(&avc->fid);
      MObtainWriteLock(&afs_xdcache, 1001);
      for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
***************
*** 1621,1626 ****
--- 1651,1752 ----
  
  }				/* afs_UFSCacheFetchProc */
  
+ /*!
+  * Get a fresh dcache from the free or discarded list.
+  *
+  * \param avc Who's dcache is this going to be?
+  * \param chunk The position where it will be placed in.
+  * \param lock How are locks held.
+  * \param ashFid If this dcache going to be used for a shadow dir,
+  * 		this is it's fid.
+  *
+  * \note Required locks:
+  * 	- afs_xdcache (W)
+  * 	- avc (R if (lock & 1) set and W otherwise)
+  * \note It write locks the new dcache. The caller must unlock it.
+  *
+  * \return The new dcache.
+  */
+ struct dcache *afs_AllocDCache(struct vcache *avc,
+ 				afs_int32 chunk,
+ 				afs_int32 lock,
+ 				struct VenusFid *ashFid)
+ {
+     struct dcache *tdc = NULL;
+     afs_uint32 size = 0;
+     struct osi_file *file;
+ 
+     if (afs_discardDCList == NULLIDX
+ 	|| ((lock & 2) && afs_freeDCList != NULLIDX)) {
+ 
+ 	afs_indexFlags[afs_freeDCList] &= ~IFFree;
+ 	tdc = afs_GetDSlot(afs_freeDCList, 0);
+ 	osi_Assert(tdc->refCount == 1);
+ 	ReleaseReadLock(&tdc->tlock);
+ 	ObtainWriteLock(&tdc->lock, 604);
+ 	afs_freeDCList = afs_dvnextTbl[tdc->index];
+ 	afs_freeDCCount--;
+     } else {
+ 	afs_indexFlags[afs_discardDCList] &= ~IFDiscarded;
+ 	tdc = afs_GetDSlot(afs_discardDCList, 0);
+ 	osi_Assert(tdc->refCount == 1);
+ 	ReleaseReadLock(&tdc->tlock);
+ 	ObtainWriteLock(&tdc->lock, 605);
+ 	afs_discardDCList = afs_dvnextTbl[tdc->index];
+ 	afs_discardDCCount--;
+ 	size =
+ 	    ((tdc->f.chunkBytes +
+ 	      afs_fsfragsize) ^ afs_fsfragsize) >> 10;
+ 	tdc->f.states &= ~(DRO|DBackup|DRW);
+ 	afs_DCMoveBucket(tdc, size, 0);
+ 	afs_blocksDiscarded -= size;
+ 	afs_stats_cmperf.cacheBlocksDiscarded = afs_blocksDiscarded;
+ 	if (lock & 2) {
+ 	    /* Truncate the chunk so zeroes get filled properly */
+ 	    file = afs_CFileOpen(tdc->f.inode);
+ 	    afs_CFileTruncate(file, 0);
+ 	    afs_CFileClose(file);
+ 	    afs_AdjustSize(tdc, 0);
+ 	}
+     }
+ 
+     /*
+      * Locks held:
+      * avc->lock(R) if setLocks
+      * avc->lock(W) if !setLocks
+      * tdc->lock(W)
+      * afs_xdcache(W)
+      */
+ 
+     /*
+      * Fill in the newly-allocated dcache record.
+      */
+     afs_indexFlags[tdc->index] &= ~(IFDirtyPages | IFAnyPages);
+     if (ashFid)
+     	/* Use shadow fid if provided. */
+ 	tdc->f.fid = *ashFid;
+     else
+     	/* Use normal vcache's fid otherwise. */
+     	tdc->f.fid = avc->fid;
+     if (avc->states & CRO)
+     	tdc->f.states = DRO;
+     else if (avc->states & CBackup)
+     	tdc->f.states = DBackup;
+     else
+     	tdc->f.states = DRW;
+     afs_DCMoveBucket(tdc, 0, afs_DCGetBucket(avc));
+     afs_indexUnique[tdc->index] = tdc->f.fid.Fid.Unique;
+     if (!ashFid)
+     	hones(tdc->f.versionNo);	/* invalid value */
+     tdc->f.chunk = chunk;
+     tdc->validPos = AFS_CHUNKTOBASE(chunk);
+     /* XXX */
+     if (tdc->lruq.prev == &tdc->lruq)
+ 	osi_Panic("lruq 1");
+ 
+     return tdc;
+ }
+ 
  /*
   * afs_GetDCache
   *
***************
*** 1721,1727 ****
  #endif /* AFS_NOSTATS */
  
      AFS_STATCNT(afs_GetDCache);
- 
      if (dcacheDisabled)
  	return NULL;
  
--- 1847,1852 ----
***************
*** 1869,1885 ****
  	 * If we didn't find the entry, we'll create one.
  	 */
  	if (index == NULLIDX) {
- 	    /* If we're disconnected, we can't do anything */
-             if (AFS_IS_DISCONNECTED) {
-                 MReleaseWriteLock(&afs_xdcache);
-                 if (setLocks) {
-                     if (slowPass)
- 	                ReleaseWriteLock(&avc->lock);
- 	            else
- 		        ReleaseReadLock(&avc->lock);
-                 }
-                 return NULL;
-             }
  	    /*
  	     * Locks held:
  	     * avc->lock(R) if setLocks
--- 1994,1999 ----
***************
*** 1902,1909 ****
  			|| afs_freeDCList != NULLIDX)
  			break;
  		    /* If we can't get space for 5 mins we give up and panic */
! 		    if (++downDCount > 300)
  			osi_Panic("getdcache");
  		    MReleaseWriteLock(&afs_xdcache);
  		    /*
  		     * Locks held:
--- 2016,2027 ----
  			|| afs_freeDCList != NULLIDX)
  			break;
  		    /* If we can't get space for 5 mins we give up and panic */
! 		    if (++downDCount > 300) {
! #if defined(AFS_CACHE_BYPASS)
! 			afs_warn("GetDCache calling osi_Panic: No space in five minutes.\n downDCount: %d\n aoffset: %d alen: %d\n", downDCount, aoffset, alen);
! #endif
  			osi_Panic("getdcache");
+                     }
  		    MReleaseWriteLock(&afs_xdcache);
  		    /*
  		     * Locks held:
***************
*** 1915,1981 ****
  		}
  	    }
  
! 	    if (afs_discardDCList == NULLIDX
! 		|| ((aflags & 2) && afs_freeDCList != NULLIDX)) {
! 
! 		afs_indexFlags[afs_freeDCList] &= ~IFFree;
! 		tdc = afs_GetDSlot(afs_freeDCList, 0);
! 		osi_Assert(tdc->refCount == 1);
! 		ReleaseReadLock(&tdc->tlock);
! 		ObtainWriteLock(&tdc->lock, 604);
! 		afs_freeDCList = afs_dvnextTbl[tdc->index];
! 		afs_freeDCCount--;
! 	    } else {
! 		afs_indexFlags[afs_discardDCList] &= ~IFDiscarded;
! 		tdc = afs_GetDSlot(afs_discardDCList, 0);
! 		osi_Assert(tdc->refCount == 1);
! 		ReleaseReadLock(&tdc->tlock);
! 		ObtainWriteLock(&tdc->lock, 605);
! 		afs_discardDCList = afs_dvnextTbl[tdc->index];
! 		afs_discardDCCount--;
! 		size =
! 		    ((tdc->f.chunkBytes +
! 		      afs_fsfragsize) ^ afs_fsfragsize) >> 10;
! 		tdc->f.states &= ~(DRO|DBackup|DRW);
! 		afs_DCMoveBucket(tdc, size, 0);
! 		afs_blocksDiscarded -= size;
! 		afs_stats_cmperf.cacheBlocksDiscarded = afs_blocksDiscarded;
! 		if (aflags & 2) {
! 		    /* Truncate the chunk so zeroes get filled properly */
! 		    file = afs_CFileOpen(tdc->f.inode);
! 		    afs_CFileTruncate(file, 0);
! 		    afs_CFileClose(file);
! 		    afs_AdjustSize(tdc, 0);
! 		}
! 	    }
! 
! 	    /*
! 	     * Locks held:
! 	     * avc->lock(R) if setLocks
! 	     * avc->lock(W) if !setLocks
! 	     * tdc->lock(W)
! 	     * afs_xdcache(W)
! 	     */
! 
! 	    /*
! 	     * Fill in the newly-allocated dcache record.
! 	     */
! 	    afs_indexFlags[tdc->index] &= ~(IFDirtyPages | IFAnyPages);
! 	    tdc->f.fid = avc->fid;
! 	    if (avc->states & CRO) 
! 		tdc->f.states = DRO;
! 	    else if (avc->states & CBackup) 
! 		tdc->f.states = DBackup;
! 	    else 
! 		tdc->f.states = DRW;
! 	    afs_DCMoveBucket(tdc, 0, afs_DCGetBucket(avc));
! 	    afs_indexUnique[tdc->index] = tdc->f.fid.Fid.Unique;
! 	    hones(tdc->f.versionNo);	/* invalid value */
! 	    tdc->f.chunk = chunk;
! 	    tdc->validPos = AFS_CHUNKTOBASE(chunk);
! 	    /* XXX */
! 	    if (tdc->lruq.prev == &tdc->lruq)
! 		osi_Panic("lruq 1");
  
  	    /*
  	     * Now add to the two hash chains - note that i is still set
--- 2033,2039 ----
  		}
  	    }
  
! 	    tdc = afs_AllocDCache(avc, chunk, aflags, NULL);
  
  	    /*
  	     * Now add to the two hash chains - note that i is still set
***************
*** 2138,2144 ****
              }
              /* Flush the Dcache */
              afs_PutDCache(tdc);
!                 
              return NULL;
          }
  	UpgradeSToWLock(&tdc->lock, 609);
--- 2196,2202 ----
              }
              /* Flush the Dcache */
              afs_PutDCache(tdc);
! 
              return NULL;
          }
  	UpgradeSToWLock(&tdc->lock, 609);
***************
*** 3557,3559 ****
--- 3615,3825 ----
      QInit(&afs_DLRU);
  
  }
+ 
+ #if defined(AFS_DISCON_ENV)
+ 
+ /*!
+  * Make a shadow copy of a dir's dcaches. It's used for disconnected
+  * operations like remove/create/rename to keep the original directory data.
+  * On reconnection, we can diff the original data with the server and get the
+  * server changes and with the local data to get the local changes.
+  *
+  * \param avc The dir vnode.
+  *
+  * \return 0 for success.
+  *
+  * \note The only lock allowed to be set is the dir's vcache entry, and it
+  * must be set in write mode.
+  * \note The vcache entry must be write locked.
+  */
+ int afs_MakeShadowDir(struct vcache *avc)
+ {
+     int j, i, index, code, ret_code = 0, offset, trans_size, block;
+     struct dcache *tdc, *new_dc = NULL;
+     struct osi_file *tfile_src, *tfile_dst;
+     struct VenusFid shadow_fid;
+     char *data;
+     int lock_held = 0;
+ 
+     /* Is this a dir? */
+     if (vType(avc) != VDIR)
+     	return ENOTDIR;
+ 
+     /* Generate a fid for the shadow dir. */
+     shadow_fid.Cell = avc->fid.Cell;
+     shadow_fid.Fid.Volume = avc->fid.Fid.Volume;
+     afs_GenShadowFid(&shadow_fid);
+ 
+     /* For each dcache, do copy it into a new fresh one. */
+     i = DVHash(&avc->fid);
+     for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
+     	/* Making sure that this isn't going to get locked twice. */
+ 	if (!lock_held) {
+ 	    /* XXX: Moved it from outside of the loop.
+ 	     * Maybe it's not quite okay because of the use of
+ 	     * dvhashTbl (once) in the for statement.
+ 	     */
+ 	    ObtainWriteLock(&afs_xdcache, 716);
+ 	    lock_held = 1;
+ 	}
+ 
+         i = afs_dvnextTbl[index];
+         if (afs_indexUnique[index] == avc->fid.Fid.Unique) {
+             tdc = afs_GetDSlot(index, NULL);
+ 
+ 	    ReleaseReadLock(&tdc->tlock);
+ 
+ 	    if (!FidCmp(&tdc->f.fid, &avc->fid)) {
+ 
+ 		/* Got a dir's dcache. */
+ 		lock_held = 0;
+ 
+ 		/* Get a fresh dcache. */
+ 		new_dc = afs_AllocDCache(avc, 0, 0, &shadow_fid);
+ 
+ 		/* Unlock hash for now. Don't need it during operations on the
+ 		 * dcache. Oh, and we can't use it because of the locking
+ 		 * hierarchy...
+ 		 */
+ 		/* XXX: So much for lock ierarchy, the afs_AllocDCache doesn't
+ 		 * respect it.
+ 		 */
+ 		//ReleaseWriteLock(&afs_xdcache);
+ 
+ 		ObtainReadLock(&tdc->lock);
+ 
+ 		/* Set up the new fid. */
+ 		/* Copy interesting data from original dir dcache. */
+ 		new_dc->mflags = tdc->mflags;
+ 		new_dc->dflags = tdc->dflags;
+ 		new_dc->f.modTime = tdc->f.modTime;
+ 		new_dc->f.versionNo = tdc->f.versionNo;
+ 		new_dc->f.states = tdc->f.states;
+ 		new_dc->f.chunk= tdc->f.chunk;
+ 		new_dc->f.chunkBytes = tdc->f.chunkBytes;
+ 
+ 		/*
+ 		 * Now add to the two hash chains - note that i is still set
+ 		 * from the above DCHash call.
+ 		 */
+ 		//ObtainWriteLock(&afs_xdcache, 713);
+ 
+ 		j = DCHash(&shadow_fid, 0);
+ 		afs_dcnextTbl[new_dc->index] = afs_dchashTbl[j];
+ 		afs_dchashTbl[j] = new_dc->index;
+ 
+ 		j = DVHash(&shadow_fid);
+ 		afs_dvnextTbl[new_dc->index] = afs_dvhashTbl[j];
+ 		afs_dvhashTbl[j] = new_dc->index;
+ 		afs_MaybeWakeupTruncateDaemon();
+ 
+ 		ReleaseWriteLock(&afs_xdcache);
+ 
+ 		/* Alloc a 4k block. */
+ 		data = (char *) afs_osi_Alloc(4096);
+ 		if (!data) {
+ 		    printf("afs_MakeShadowDir: could not alloc data\n");
+ 		    ret_code = ENOMEM;
+ 		    goto done;
+ 		}
+ 
+ 		/* Open the files. */
+ 		tfile_src = afs_CFileOpen(tdc->f.inode);
+ 		tfile_dst = afs_CFileOpen(new_dc->f.inode);
+ 
+ 		/* Init no of blocks to be read and offset. */
+ 		block = (tdc->f.chunkBytes / 4096);
+ 		offset = 0;
+ 
+ 		/* And now copy dir dcache data into this dcache,
+ 		 * 4k at a time.
+ 		 */
+ 		while (block >= 0) {
+ 
+ 		    /* Last chunk might have less bytes to transfer. */
+ 		    if (!block) {
+ 		    	/* Last block. */
+ 		    	trans_size = (tdc->f.chunkBytes % 4096);
+ 			if (!trans_size)
+ 			    /* An exact no of 4k blocks. */
+ 			    break;
+ 		    } else
+ 		    	trans_size = 4096;
+ 
+ 		    /* Read a chunk from the dcache. */
+ 		    code = afs_CFileRead(tfile_src, offset, data, trans_size);
+ 		    if (code < trans_size) {
+ 		    	/* Can't access file, stop doing stuff and return error. */
+ 		    	ret_code = EIO;
+ 		    	break;
+ 		    }
+ 
+ 		    /* Write it to the new dcache. */
+ 		    code = afs_CFileWrite(tfile_dst, offset, data, trans_size);
+ 		    if (code < trans_size) {
+ 		    	ret_code = EIO;
+ 		    	break;
+ 		    }
+ 
+ 		    block--;
+ 		    offset += 4096;
+ 		}		/* while (block) */
+ 
+ 		afs_CFileClose(tfile_dst);
+ 		afs_CFileClose(tfile_src);
+ 
+ 		afs_osi_Free(data, 4096);
+ 
+ 		ReleaseWriteLock(&new_dc->lock);
+ 		ReleaseReadLock(&tdc->lock);
+ 
+ 		afs_PutDCache(new_dc);
+ 	    }			/* if dcache fid match */
+             afs_PutDCache(tdc);
+         }			/* if unuiquifier match */
+     }
+ done:
+     if (lock_held)
+ 	ReleaseWriteLock(&afs_xdcache);
+ 
+     if (!ret_code) {
+     	if (!avc->ddirty_flags) {
+ 	    ObtainWriteLock(&afs_DDirtyVCListLock, 763);
+ 	    AFS_DISCON_ADD_DIRTY(avc);
+ 	    ReleaseWriteLock(&afs_DDirtyVCListLock);
+ 	}
+ 	avc->shVnode = shadow_fid.Fid.Vnode;
+ 	avc->shUnique = shadow_fid.Fid.Unique;
+ 	avc->ddirty_flags |= VDisconShadowed;
+     }
+ 
+     return ret_code;
+ }
+ 
+ /*!
+  * Delete the dcaches of a shadow dir.
+  *
+  * \param avc The vcache containing the shadow fid.
+  *
+  * \note avc must be write locked.
+  */
+ void afs_DeleteShadowDir(struct vcache *avc)
+ {
+     struct dcache *tdc;
+     struct VenusFid shadow_fid;
+ 
+     shadow_fid.Cell = avc->fid.Cell;
+     shadow_fid.Fid.Volume = avc->fid.Fid.Volume;
+     shadow_fid.Fid.Vnode = avc->shVnode;
+     shadow_fid.Fid.Unique = avc->shUnique;
+ 
+     tdc = afs_FindDCacheByFid(&shadow_fid);
+     if (tdc) {
+     	afs_HashOutDCache(tdc, 1);
+ 	afs_DiscardDCache(tdc);
+     	afs_PutDCache(tdc);
+     }
+     /* Remove shadowed dir flag. */
+     avc->ddirty_flags &= ~VDisconShadowed;
+ }
+ #endif
Index: openafs/src/afs/afs_disconnected.c
diff -c openafs/src/afs/afs_disconnected.c:1.2.2.2 openafs/src/afs/afs_disconnected.c:1.2.2.3
*** openafs/src/afs/afs_disconnected.c:1.2.2.2	Fri May 23 10:25:15 2008
--- openafs/src/afs/afs_disconnected.c	Mon Sep 22 15:29:54 2008
***************
*** 3,18 ****
   * License.  For details, see the LICENSE file in the top-level source
   * directory or online at http://www.openafs.org/dl/license10.html
   */
!  
  #include <afsconfig.h>
  #include "afs/param.h"
   
! RCSID("$Header: /cvs/openafs/src/afs/afs_disconnected.c,v 1.2.2.2 2008/05/23 14:25:15 shadow Exp $");
   
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
!  
  #ifdef AFS_DISCON_ENV
  
! /* Nothing here any more. Remove from the build unless stuff comes back! */
  #endif
--- 3,1486 ----
   * License.  For details, see the LICENSE file in the top-level source
   * directory or online at http://www.openafs.org/dl/license10.html
   */
! 
  #include <afsconfig.h>
  #include "afs/param.h"
   
! RCSID("$Header: /cvs/openafs/src/afs/afs_disconnected.c,v 1.2.2.3 2008/09/22 19:29:54 shadow Exp $");
   
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
! #include "afs/afs_stats.h"	/* statistics */
! #include "afs/lock.h"
! #include "afs/afs_cbqueue.h"
! 
  #ifdef AFS_DISCON_ENV
  
! #define dv_match(vc, fstat) 				 \
! 	((vc->m.DataVersion.low == fstat.DataVersion) && \
!      	(vc->m.DataVersion.high == fstat.dataVersionHigh))
! 
! /*! Global list of dirty vcaches. */
! /*! Last added element. */
! struct vcache *afs_DDirtyVCList = NULL;
! /*! Head of list. */
! struct vcache *afs_DDirtyVCListStart = NULL;
! /*! Previous element in the list. */
! struct vcache *afs_DDirtyVCListPrev = NULL;
! 
! /*! Locks list of dirty vcaches. */
! afs_rwlock_t afs_DDirtyVCListLock;
! 
! extern afs_int32 *afs_dvhashTbl;	/*Data cache hash table */
! extern afs_int32 *afs_dchashTbl;	/*Data cache hash table */
! extern afs_int32 *afs_dvnextTbl;	/*Dcache hash table links */
! extern afs_int32 *afs_dcnextTbl;	/*Dcache hash table links */
! extern struct dcache **afs_indexTable;	/*Pointers to dcache entries */
! 
! /*! Vnode number. On file creation, use the current
!  *  value and increment it.
!  */
! afs_uint32 afs_DisconVnode = 2;
! 
! /*! Conflict policy. */
! enum {
! 	CLIENT_WINS = 0,
! 	SERVER_WINS,
! 	LAST_CLOSER_WINS,
! 	ASK
! };
! 
! afs_int32 afs_ConflictPolicy = SERVER_WINS;
! 
! /*!
!  * Find the first dcache of a file that has the specified fid.
!  * Similar to afs_FindDCache, only that it takes a fid instead
!  * of a vcache and it can get the first dcache.
!  *
!  * \param afid
!  *
!  * \return The found dcache or NULL.
!  */
! struct dcache *afs_FindDCacheByFid(register struct VenusFid *afid)
! {
!     register afs_int32 i, index;
!     register struct dcache *tdc = NULL;
! 
!     i = DVHash(afid);
!     ObtainWriteLock(&afs_xdcache, 758);
!     for (index = afs_dvhashTbl[i]; index != NULLIDX;) {
! 	if (afs_indexUnique[index] == afid->Fid.Unique) {
! 	    tdc = afs_GetDSlot(index, NULL);
! 	    ReleaseReadLock(&tdc->tlock);
! 	    if (!FidCmp(&tdc->f.fid, afid)) {
! 		break;		/* leaving refCount high for caller */
! 	    }
! 	    afs_PutDCache(tdc);
! 	}
! 	index = afs_dvnextTbl[index];
!     }
!     ReleaseWriteLock(&afs_xdcache);
! 
!     if (index == NULLIDX)
!     	tdc = NULL;
!     return tdc;
! }
! 
! /*!
!  * Generate a store status from a dirty vcache entry.
!  *
!  * \param avc Dirty vcache entry.
!  * \param astat
!  *
!  * \note The vnode must be share locked. It is called only on resync,
!  * where the vnode is write locked locally and and the server.
!  *
!  * \return Mask of operations.
!  */
! int afs_GenStoreStatus(struct vcache *avc, struct AFSStoreStatus *astat)
! {
!     if (!avc || !astat || !avc->ddirty_flags)
!     	return 0;
! 
!     /* Clean up store stat. */
!     memset(astat, 0, sizeof(struct AFSStoreStatus));
! 
!     if (avc->ddirty_flags & VDisconSetTime) {
! 	/* Update timestamp. */
! 	astat->ClientModTime = avc->m.Date;
! 	astat->Mask |= AFS_SETMODTIME;
!     }
! 
!     if (avc->ddirty_flags & VDisconSetMode) {
! 	/* Copy the mode bits. */
! 	astat->UnixModeBits = avc->m.Mode;
! 	astat->Mask |= AFS_SETMODE;
!    }
! 
!    /* XXX: more to come... ?*/
! 
!    return astat->Mask;
! }
! 
! /*!
!  * Hook for filtering the local dir fid by searching the "." entry.
!  *
!  * \param hdata The fid to be filled.
!  */
! int get_parent_dir_fid_hook(void *hdata,
! 				char *aname,
! 				afs_int32 vnode,
! 				afs_int32 unique)
! {
!     struct VenusFid *tfid = (struct VenusFid *) hdata;
! 
!     if ((aname[0] == '.') && (aname[1] == '.') && !aname[2]) {
!     	tfid->Fid.Vnode = vnode;
! 	tfid->Fid.Unique = unique;
! 	return 1;
!     }
! 
!     return 0;
! }
! 
! /*!
!  * Get a the dir's fid by looking in the vcache for simple files and
!  * in the ".." entry for directories.
!  *
!  * \param avc The file's vhash entry.
!  * \param afid Put the fid here.
!  */
! int afs_GetParentDirFid(struct vcache *avc, struct VenusFid *afid)
! {
!     struct dcache *tdc;
! 
!     afid->Cell = avc->fid.Cell;
!     afid->Fid.Volume = avc->fid.Fid.Volume;
! 
!     if (vType(avc) == VREG) {
! 	/* Normal files have the dir fid embedded in the vcache. */
! 	afid->Fid.Vnode = avc->parentVnode;
! 	afid->Fid.Unique = avc->parentUnique;
! 
!     } else if (vType(avc) == VDIR) {
! 	/* If dir or parent dir created locally*/
! 	tdc = afs_FindDCacheByFid(&avc->fid);
!     	if (tdc) {
! 	    /* Lookup each entry for the fid. It should be the first. */
!     	    afs_dir_EnumerateDir(tdc, &get_parent_dir_fid_hook, afid);
!     	    afs_PutDCache(tdc);
! 	}
!     }
! 
!     return 0;
! }
! 
! struct NameAndFid {
!     struct VenusFid *fid;
!     char *name;
!     int name_len;
! };
! 
! /*!
!  * Hook that searches a certain fid's name.
!  *
!  * \param hdata NameAndFid structure containin a pointer to a fid
!  * and an allocate name. The name will be filled when hit.
!  */
! int get_vnode_name_hook(void *hdata,
! 				char *aname,
! 				afs_int32 vnode,
! 				afs_int32 unique)
! {
!     struct NameAndFid *nf = (struct NameAndFid *) hdata;
! 
!     if ((nf->fid->Fid.Vnode == vnode) &&
!     	(nf->fid->Fid.Unique == unique)) {
! 	nf->name_len = strlen(aname);
! 	memcpy(nf->name, aname, nf->name_len);
! 	nf->name[nf->name_len] = 0;
! 
! 	return 1;
!     }
! 
!     return 0;
! }
! 
! /*!
!  * Try to get a vnode's name by comparing all parent dir's entries
!  * to the given fid. It can also return the dir's dcache.
!  *
!  * \param avc The file's vcache.
!  * \param afid The parent dir's fid.
!  * \param aname A preallocated string for the name.
!  * \param deleted Has this file been deleted? If yes, use the shadow
!  * dir for looking up the name.
!  */
! int afs_GetVnodeName(struct vcache *avc,
! 			struct VenusFid *afid,
! 			char *aname,
! 			int deleted)
! {
!     int code = 0;
!     struct dcache *tdc;
!     struct vcache *parent_vc;
!     struct NameAndFid tnf;
!     struct VenusFid parent_fid;
!     struct VenusFid shadow_fid;
! 
!     /* List dir contents and get it's tdc. */
!     if (deleted) {
! 	/* For deleted files, get the shadow dir's tdc: */
! 
! 	/* Get the parent dir's vcache that contains the shadow fid. */
! 	parent_fid.Cell = avc->fid.Cell;
! 	parent_fid.Fid.Volume = avc->fid.Fid.Volume;
! 	if (avc->ddirty_flags & VDisconRename) {
! 	    /* For renames the old dir fid is needed. */
! 	    parent_fid.Fid.Vnode = avc->oldVnode;
! 	    parent_fid.Fid.Unique = avc->oldUnique;
! 	} else {
! 	    parent_fid.Fid.Vnode = afid->Fid.Vnode;
! 	    parent_fid.Fid.Unique = afid->Fid.Unique;
! 	}
! 
! 	/* Get the parent dir's vcache that contains the shadow fid. */
! 	ObtainSharedLock(&afs_xvcache, 755);
! 	parent_vc = afs_FindVCache(&parent_fid, 0, 1);
! 	ReleaseSharedLock(&afs_xvcache);
! 	if (!parent_vc) {
! 	    return ENOENT;
! 	}
! 
! 	shadow_fid.Cell = parent_vc->fid.Cell;
!     	shadow_fid.Fid.Volume = parent_vc->fid.Fid.Volume;
!     	shadow_fid.Fid.Vnode = parent_vc->shVnode;
!     	shadow_fid.Fid.Unique = parent_vc->shUnique;
! 
! 	afs_PutVCache(parent_vc);
! 
! 	/* Get shadow dir's dcache. */
! 	tdc = afs_FindDCacheByFid(&shadow_fid);
! 
!     } else {
! 
! 	/* For normal files, look into the current dir's entry. */
! 	tdc = afs_FindDCacheByFid(afid);
!     }			/* if (deleted) */
! 
!     if (tdc) {
! 	tnf.fid = &avc->fid;
!    	tnf.name_len = 0;
!     	tnf.name = aname;
!     	afs_dir_EnumerateDir(tdc, &get_vnode_name_hook, &tnf);
! 	afs_PutDCache(tdc);
!     } else {
!         code = ENOENT;
!     }
! 
!     return code;
! }
! 
! struct DirtyChildrenCount {
!     struct vcache *vc;
!     afs_uint32 count;
! };
! 
! /*!
!  * Lookup dirty deleted vnodes in this dir.
!  */
! int chk_del_children_hook(void *hdata,
! 				char *aname,
! 				afs_int32 vnode,
! 				afs_int32 unique)
! {
!     struct VenusFid tfid;
!     struct DirtyChildrenCount *v = (struct DirtyChildrenCount *) hdata;
!     struct vcache *tvc;
! 
!     if ((aname[0] == '.') && !aname[1])
!     	/* Skip processing this dir again.
! 	 * It would result in an endless loop.
! 	 */
! 	return 0;
! 
!     if ((aname[0] == '.') && (aname[1] == '.') && !aname[2])
!     	/* Don't process parent dir. */
!     	return 0;
! 
!     /* Get this file's vcache. */
!     tfid.Cell = v->vc->fid.Cell;
!     tfid.Fid.Volume = v->vc->fid.Fid.Volume;
!     tfid.Fid.Vnode = vnode;
!     tfid.Fid.Unique = unique;
! 
!     ObtainSharedLock(&afs_xvcache, 757);
!     tvc = afs_FindVCache(&tfid, 0, 1);
!     ReleaseSharedLock(&afs_xvcache);
! 
!     /* Count unfinished dirty children. VDisconShadowed can still be set,
!      * because we need it to remove the shadow dir.
!      */
!     if (tvc && tvc->ddirty_flags) {
! 	v->count++;
! 	afs_PutVCache(tvc);
!     }
! 
!     return 0;
! }
! 
! /*!
!  * Check if entries have been deleted in a vnode's shadow
!  * dir.
!  *
!  * \return Returns the number of dirty children.
!  *
!  * \note afs_DDirtyVCListLock must be write locked.
!  */
! int afs_CheckDeletedChildren(struct vcache *avc)
! {
!     struct dcache *tdc;
!     struct DirtyChildrenCount dcc;
!     struct VenusFid shadow_fid;
! 
!     if (!(avc->ddirty_flags & VDisconShadowed))
!     	/* Empty dir. */
!     	return 0;
! 
!     shadow_fid.Cell = avc->fid.Cell;
!     shadow_fid.Fid.Volume = avc->fid.Fid.Volume;
!     shadow_fid.Fid.Vnode = avc->shVnode;
!     shadow_fid.Fid.Unique = avc->shUnique;
! 
!     dcc.count = 0;
! 
!     /* Get shadow dir's dcache. */
!     tdc = afs_FindDCacheByFid(&shadow_fid);
!     if (tdc) {
! 	dcc.vc = avc;
! 	afs_dir_EnumerateDir(tdc, &chk_del_children_hook, &dcc);
! 	afs_PutDCache(tdc);
!     }
! 
!     return dcc.count;
! }
! 
! /*!
!  * Changes a file's parent fid references.
!  */
! int fix_children_fids_hook(void *hdata,
! 				char *aname,
! 				afs_int32 vnode,
! 				afs_int32 unique)
! {
!     struct VenusFid tfid;
!     struct VenusFid *afid = (struct VenusFid *) hdata;
!     struct vcache *tvc;
!     struct dcache *tdc = NULL;
! 
!     if ((aname[0] == '.') && !aname[1])
! 	return 0;
! 
!     if ((aname[0] == '.') && (aname[1] == '.') && !aname[2])
!     	return 0;
! 
!     tfid.Cell = afid->Cell;
!     tfid.Fid.Volume = afid->Fid.Volume;
!     tfid.Fid.Vnode = vnode;
!     tfid.Fid.Unique = unique;
! 
!     if (!(vnode % 2)) {
! 	/* vnode's parity indicates that it's a file. */
! 
! 	/* Get the vcache. */
! 	ObtainSharedLock(&afs_xvcache, 759);
! 	tvc = afs_FindVCache(&tfid, 0, 1);
! 	ReleaseSharedLock(&afs_xvcache);
! 
! 	/* Change the fields. */
! 	if (tvc) {
! 	    tvc->parentVnode = afid->Fid.Vnode;
! 	    tvc->parentUnique = afid->Fid.Unique;
! 
! 	    afs_PutVCache(tvc);
! 	}
!     } else {
!     	/* It's a dir. Fix this dir's .. entry to contain the new fid. */
! 	/* Seek the dir's dcache. */
!     	tdc = afs_FindDCacheByFid(&tfid);
! 	if (tdc) {
! 	    /* Change the .. entry fid. */
! 	    afs_dir_ChangeFid(tdc, "..", NULL, &afid->Fid.Vnode);
! 	    afs_PutDCache(tdc);
! 	}
!     }			/* if (!(vnode % 2))*/
! 
!     return 0;
! }
! 
! /*!
!  * Fixes the parentVnode and parentUnique fields of all
!  * files (not dirs) contained in the directory pointed by
!  * old_fid. This is useful on resync, when a locally created dir
!  * get's a new fid and all the children references must be updated
!  * to reflect the new fid.
!  *
!  * \note The dir's fid hasn't been changed yet, it is still referenced
!  * with the old fid.
!  *
!  * \param old_fid The current dir's fid.
!  * \param new_fid The new dir's fid.
!  */
! void afs_FixChildrenFids(struct VenusFid *old_fid, struct VenusFid *new_fid)
! {
!     struct dcache *tdc;
! 
!     /* Get shadow dir's dcache. */
!     tdc = afs_FindDCacheByFid(old_fid);
!     /* Change the fids. */
!     if (tdc) {
! 	afs_dir_EnumerateDir(tdc, &fix_children_fids_hook, new_fid);
! 	afs_PutDCache(tdc);
!     }
! }
! 
! int list_dir_hook(void *hdata, char *aname, afs_int32 vnode, afs_int32 unique)
! {
!     printf("list_dir_hook: %s v:%u u:%u\n", aname, vnode, unique);
!     return 0;
! }
! 
! void afs_DbgListDirEntries(struct VenusFid *afid)
! {
!     struct dcache *tdc;
! 
!     /* Get shadow dir's dcache. */
!     tdc = afs_FindDCacheByFid(afid);
!     if (tdc) {
! 	afs_dir_EnumerateDir(tdc, &list_dir_hook, NULL);
! 	afs_PutDCache(tdc);
!     }
! }
! 
! /*!
!  * Handles file renaming on reconnection:
!  * - Get the old name from the old dir's shadow dir.
!  * - Get the new name from the current dir.
!  * - Old dir fid and new dir fid are collected along the way.
!  * */
! int afs_ProcessOpRename(struct vcache *avc, struct vrequest *areq)
! {
!     struct VenusFid old_pdir_fid, new_pdir_fid;
!     char *old_name, *new_name;
!     struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
!     struct AFSVolSync tsync;
!     struct conn *tc;
!     afs_uint32 code = 0;
!     XSTATS_DECLS;
! 
!     /* Get old dir vcache. */
!     old_pdir_fid.Cell = avc->fid.Cell;
!     old_pdir_fid.Fid.Volume = avc->fid.Fid.Volume;
!     old_pdir_fid.Fid.Vnode = avc->oldVnode;
!     old_pdir_fid.Fid.Unique = avc->oldUnique;
! 
!     /* Get old name. */
!     old_name = (char *) afs_osi_Alloc(AFSNAMEMAX);
!     if (!old_name) {
! 	printf("afs_ProcessOpRename: Couldn't alloc space for old name.\n");
! 	return ENOMEM;
!     }
!     code = afs_GetVnodeName(avc, &old_pdir_fid, old_name, 1);
!     if (code) {
! 	printf("afs_ProcessOpRename: Couldn't find old name.\n");
! 	code = ENOENT;
! 	goto end2;
!     }
! 
!     /* Alloc data first. */
!     new_name = (char *) afs_osi_Alloc(AFSNAMEMAX);
!     if (!new_name) {
! 	printf("afs_ProcessOpRename: Couldn't alloc space for new name.\n");
! 	code = ENOMEM;
! 	goto end2;
!     }
! 
!     if (avc->ddirty_flags & VDisconRenameSameDir) {
!     	/* If we're in the same dir, don't do the lookups all over again,
! 	 * just copy fid and vcache from the old dir.
! 	 */
! 	memcpy(&new_pdir_fid, &old_pdir_fid, sizeof(struct VenusFid));
!     } else {
! 	/* Get parent dir's FID.*/
!     	new_pdir_fid.Fid.Unique = 0;
!     	afs_GetParentDirFid(avc, &new_pdir_fid);
!     	if (!new_pdir_fid.Fid.Unique) {
! 	    printf("afs_ProcessOpRename: Couldn't find new parent dir FID.\n");
! 	    code = ENOENT;
! 	    goto end1;
!         }
!     }
! 
!     /* And finally get the new name. */
!     code = afs_GetVnodeName(avc, &new_pdir_fid, new_name, 0);
!     if (code) {
! 	printf("afs_ProcessOpRename: Couldn't find new name.\n");
! 	code = ENOENT;
! 	goto end1;
!     }
! 
!     /* Send to data to server. */
!     do {
!     	tc = afs_Conn(&old_pdir_fid, areq, SHARED_LOCK);
!     	if (tc) {
! 	    XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
! 	    RX_AFS_GUNLOCK();
! 	    code = RXAFS_Rename(tc->id,
! 	    	(struct AFSFid *)&old_pdir_fid.Fid,
! 		old_name,
! 		(struct AFSFid *)&new_pdir_fid.Fid,
! 		new_name,
! 		&OutOldDirStatus,
! 		&OutNewDirStatus,
! 		&tsync);
! 	    RX_AFS_GLOCK();
! 	    XSTATS_END_TIME;
!         } else
! 	    code = -1;
! 
!     } while (afs_Analyze(tc,
!     		code,
! 		&new_pdir_fid,
! 		areq,
! 		AFS_STATS_FS_RPCIDX_RENAME,
! 		SHARED_LOCK,
! 		NULL));
! 
!     if (code)
!     	printf("afs_ProcessOpRename: server code=%u\n", code);
! end1:
!     afs_osi_Free(new_name, AFSNAMEMAX);
! end2:
!     afs_osi_Free(old_name, AFSNAMEMAX);
!     return code;
! }
! 
! /*!
!  * Handles all the reconnection details:
!  * - Get all the details about the vnode: name, fid, and parent dir fid.
!  * - Send data to server.
!  * - Handle errors.
!  * - Reorder vhash and dcaches in their hashes, using the newly acquired fid.
!  */
! int afs_ProcessOpCreate(struct vcache *avc,
! 				struct vrequest *areq,
! 				struct AFS_UCRED *acred)
! {
!     char *tname = NULL;
!     struct AFSStoreStatus InStatus;
!     struct AFSFetchStatus OutFidStatus, OutDirStatus;
!     struct VenusFid pdir_fid, newFid;
!     struct server *hostp = NULL;
!     struct AFSCallBack CallBack;
!     struct AFSVolSync tsync;
!     struct vcache *tdp = NULL, *tvc = NULL;
!     struct dcache *tdc = NULL;
!     struct conn *tc;
!     afs_int32 now, hash, new_hash, index;
!     int code = 0;
!     XSTATS_DECLS;
! 
!     /* Get parent dir's FID. */
!     pdir_fid.Fid.Unique = 0;
!     afs_GetParentDirFid(avc, &pdir_fid);
!     if (!pdir_fid.Fid.Unique) {
! 	printf("afs_ProcessOpCreate: Couldn't find parent dir'sFID.\n");
! 	return ENOENT;
!     }
! 
!     tname = afs_osi_Alloc(AFSNAMEMAX);
!     if (!tname) {
! 	printf("afs_ProcessOpCreate: Couldn't find file name\n");
! 	return ENOMEM;
!     }
! 
!     /* Get vnode's name. */
!     code = afs_GetVnodeName(avc, &pdir_fid, tname, 0);
!     if (code) {
! 	printf("afs_ProcessOpCreate: Couldn't find file name\n");
! 	code = ENOENT;
! 	goto end;
!     }
! 
!     /* Get parent dir vcache. */
!     ObtainSharedLock(&afs_xvcache, 760);
!     tdp = afs_FindVCache(&pdir_fid, 0, 1);
!     ReleaseSharedLock(&afs_xvcache);
!     if (!tdp) {
! 	printf("afs_ProcessOpCreate: Couldn't find parent dir's vcache\n");
! 	code = ENOENT;
! 	goto end;
!     }
! 
!     if (tdp->ddirty_flags & VDisconCreate) {
!     	/* If the parent dir has been created locally, defer
! 	 * this vnode for later by moving it to the end.
! 	 */
! 	afs_DDirtyVCList->ddirty_next = avc;
! 	afs_DDirtyVCList = avc;
! 	printf("afs_ProcessOpRemove: deferring this vcache\n");
!     	code = ENOTEMPTY;
! 	goto end;
!     }
! 
!     /* Set status. */
!     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
!     InStatus.ClientModTime = avc->m.Date;
!     InStatus.Owner = avc->m.Owner;
!     InStatus.Group = (afs_int32) acred->cr_gid;
!     /* Only care about protection bits. */
!     InStatus.UnixModeBits = avc->m.Mode & 0xffff;
! 
!     /* Connect to server. */
!     if (vType(avc) == VREG) {
!         /* Make file on server. */
!         do {
!             tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK);
!             if (tc) {
! 		/* Remember for callback processing. */
!                 hostp = tc->srvr->server;
!                 now = osi_Time();
!                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
!                 RX_AFS_GUNLOCK();
!                 code = RXAFS_CreateFile(tc->id,
!                                 (struct AFSFid *)&tdp->fid.Fid,
!                                 tname,
!                                 &InStatus,
!                                 (struct AFSFid *) &newFid.Fid,
!                                 &OutFidStatus,
!                                 &OutDirStatus,
!                                 &CallBack,
!                                 &tsync);
!                 RX_AFS_GLOCK();
!                 XSTATS_END_TIME;
!                 CallBack.ExpirationTime += now;
!             } else
!                 code = -1;
!         } while (afs_Analyze(tc,
!                         code,
!                         &tdp->fid,
!                         areq,
!                         AFS_STATS_FS_RPCIDX_CREATEFILE,
!                         SHARED_LOCK,
!                         NULL));
! 
!     } else if (vType(avc) == VDIR) {
!         /* Make dir on server. */
!         do {
!             tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK);
!             if (tc) {
!                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
!                 now = osi_Time();
!                 RX_AFS_GUNLOCK();
!                 code = RXAFS_MakeDir(tc->id,
!                                 (struct AFSFid *) &tdp->fid.Fid,
!                                 tname,
!                                 &InStatus,
!                                 (struct AFSFid *) &newFid.Fid,
!                                 &OutFidStatus,
!                                 &OutDirStatus,
!                                 &CallBack,
!                                 &tsync);
!                 RX_AFS_GLOCK();
!                 XSTATS_END_TIME;
!                 CallBack.ExpirationTime += now;
!                 /* DON'T forget to set the callback at some point. */
!             } else
!                code = -1;
!          } while (afs_Analyze(tc,
!                         code,
!                         &tdp->fid,
!                         areq,
!                         AFS_STATS_FS_RPCIDX_MAKEDIR,
!                         SHARED_LOCK,
!                         NULL));
!     }					/* Do server changes. */
! 
!     /* TODO: Handle errors. */
!     if (code) {
! 	printf("afs_ProcessOpCreate: error while creating vnode on server, code=%d .\n", code);
! 	code = EIO;
! 	goto end;
!     }
! 
!     /* The rpc doesn't set the cell number. */
!     newFid.Cell = avc->fid.Cell;
! 
!     /*
!      * Change the fid in the dir entry.
!      */
! 
!     /* Seek the dir's dcache. */
!     tdc = afs_FindDCacheByFid(&tdp->fid);
!     if (tdc) {
!     	/* And now change the fid in the parent dir entry. */
!     	afs_dir_ChangeFid(tdc, tname, &avc->fid.Fid.Vnode, &newFid.Fid.Vnode);
!     	afs_PutDCache(tdc);
!     }
! 
!     if (vType(avc) == VDIR) {
! 	/* Change fid in the dir for the "." entry. ".." has alredy been
! 	 * handled by afs_FixChildrenFids when processing the parent dir.
! 	 */
! 	tdc = afs_FindDCacheByFid(&avc->fid);
! 	if (tdc) {
!    	    afs_dir_ChangeFid(tdc, ".", &avc->fid.Fid.Vnode, &newFid.Fid.Vnode);
! 
! 	    if (avc->m.LinkCount >= 2)
! 	        /* For non empty dirs, fix children's parentVnode and parentUnique
! 	    	 * reference.
! 	     	 */
! 	    	afs_FixChildrenFids(&avc->fid, &newFid);
! 
! 	    afs_PutDCache(tdc);
! 	}
!     }
! 
!     /* Recompute hash chain positions for vnode and dcaches.
!      * Then change to the new FID.
!      */
! 
!     /* The vcache goes first. */
!     ObtainWriteLock(&afs_xvcache, 735);
! 
!     /* Old fid hash. */
!     hash = VCHash(&avc->fid);
!     /* New fid hash. */
!     new_hash = VCHash(&newFid);
! 
!     /* Remove hash from old position. */
!     /* XXX: not checking array element contents. It shouldn't be empty.
!      * If it oopses, then something else might be wrong.
!      */
!     if (afs_vhashT[hash] == avc) {
!         /* First in hash chain (might be the only one). */
! 	afs_vhashT[hash] = avc->hnext;
!     } else {
!         /* More elements in hash chain. */
!  	//for (tvc = afs_vhashT[hash]; tdp; tdp = tdp->hnext) {
!  	for (tvc = afs_vhashT[hash]; tvc; tvc = tvc->hnext) {
! 	    if (tvc->hnext == avc) {
! 		tvc->hnext = avc->hnext;
! 		break;
! 	    }
!         }
!     }                           /* if (!afs_vhashT[i]->hnext) */
!     QRemove(&afs_vhashTV[hash]);
! 
!     /* Insert hash in new position. */
!     avc->hnext = afs_vhashT[new_hash];
!     afs_vhashT[new_hash] = avc;
!     QAdd(&afs_vhashTV[new_hash], &avc->vhashq);
! 
!     ReleaseWriteLock(&afs_xvcache);
! 
!     /* Do the same thing for all dcaches. */
!     hash = DVHash(&avc->fid);
!     ObtainWriteLock(&afs_xdcache, 743);
!     for (index = afs_dvhashTbl[hash]; index != NULLIDX; index = hash) {
!         hash = afs_dvnextTbl[index];
!         tdc = afs_GetDSlot(index, NULL);
!         ReleaseReadLock(&tdc->tlock);
! 	if (afs_indexUnique[index] == avc->fid.Fid.Unique) {
!             if (!FidCmp(&tdc->f.fid, &avc->fid)) {
! 
! 		/* Safer but slower. */
!  		afs_HashOutDCache(tdc, 0);
! 
!                 /* Put dcache in new positions in the dchash and dvhash. */
!  		new_hash = DCHash(&newFid, tdc->f.chunk);
!  		afs_dcnextTbl[tdc->index] = afs_dchashTbl[new_hash];
!  		afs_dchashTbl[new_hash] = tdc->index;
! 
!  		new_hash = DVHash(&newFid);
!  		afs_dvnextTbl[tdc->index] = afs_dvhashTbl[new_hash];
!  		afs_dvhashTbl[new_hash] = tdc->index;
! 
!  		afs_indexUnique[tdc->index] = newFid.Fid.Unique;
! 		memcpy(&tdc->f.fid, &newFid, sizeof(struct VenusFid));
!                 //afs_MaybeWakeupTruncateDaemon();
!            }                   /* if fid match */
! 	}                       /* if uniquifier match */
!     	if (tdc)
! 	    afs_PutDCache(tdc);
!     }                           /* for all dcaches in this hash bucket */
!     ReleaseWriteLock(&afs_xdcache);
! 
!     /* Now we can set the new fid. */
!     memcpy(&avc->fid, &newFid, sizeof(struct VenusFid));
! 
!     if (tdp) {
!     	/* Unset parent dir CStat flag, so it will get refreshed on next
! 	 * online stat.
! 	 */
! 	ObtainWriteLock(&tdp->lock, 745);
! 	tdp->states &= ~CStatd;
!     	ReleaseWriteLock(&tdp->lock);
!     }
! end:
!     if (tdp)
!     	afs_PutVCache(tdp);
!     afs_osi_Free(tname, AFSNAMEMAX);
!     return code;
! }
! 
! /*!
!  * Remove a vnode on the server, be it file or directory.
!  * Not much to do here only get the parent dir's fid and call the
!  * removel rpc.
!  *
!  * \param avc The deleted vcache
!  * \param areq
!  *
!  * \note The vcache refcount should be dropped because it points to
!  * a deleted vnode and has served it's purpouse, but we drop refcount
!  * on shadow dir deletio (we still need it for that).
!  *
!  * \note avc must be write locked.
!  */
! int afs_ProcessOpRemove(struct vcache *avc, struct vrequest *areq)
! {
!     char *tname = NULL;
!     struct AFSFetchStatus OutDirStatus;
!     struct VenusFid pdir_fid;
!     struct AFSVolSync tsync;
!     struct conn *tc;
!     struct vcache *tdp = NULL;
!     int code = 0;
!     XSTATS_DECLS;
! 
!     /* Get parent dir's FID. */
!     pdir_fid.Fid.Unique = 0;
!     afs_GetParentDirFid(avc, &pdir_fid);
!     if (!pdir_fid.Fid.Unique) {
! 	printf("afs_ProcessOpRemove: Couldn't find parent dir's FID.\n");
! 	return ENOENT;
!     }
! 
!     tname = afs_osi_Alloc(AFSNAMEMAX);
!     if (!tname) {
! 	printf("afs_ProcessOpRemove: Couldn't find file name\n");
! 	return ENOMEM;
!     }
! 
!     /* Get file name. */
!     code = afs_GetVnodeName(avc, &pdir_fid, tname, 1);
!     if (code) {
! 	printf("afs_ProcessOpRemove: Couldn't find file name\n");
! 	code = ENOENT;
! 	goto end;
!     }
! 
!     if ((vType(avc) == VDIR) && (afs_CheckDeletedChildren(avc))) {
! 	/* Deleted children of this dir remain unsynchronized.
! 	 * Defer this vcache.
! 	 */
! 	afs_DDirtyVCList->ddirty_next = avc;
! 	afs_DDirtyVCList = avc;
!     	code = ENOTEMPTY;
! 	goto end;
!     }
! 
!     if (vType(avc) == VREG) {
!     	/* Remove file on server. */
! 	do {
! 	    tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK);
! 	    if (tc) {
! 	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
! 		RX_AFS_GUNLOCK();
! 		code = RXAFS_RemoveFile(tc->id,
! 				&pdir_fid.Fid,
! 				tname,
! 				&OutDirStatus,
! 				&tsync);
! 
! 		RX_AFS_GLOCK();
! 		XSTATS_END_TIME;
! 	    } else
! 		code = -1;
! 	} while (afs_Analyze(tc,
! 			code,
! 			&pdir_fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_REMOVEFILE,
! 			SHARED_LOCK,
! 			NULL));
! 
!     } else if (vType(avc) == VDIR) {
!     	/* Remove dir on server. */
! 	do {
! 	    tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK);
! 	    if (tc) {
! 		XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
! 		RX_AFS_GUNLOCK();
! 		code = RXAFS_RemoveDir(tc->id,
! 				&pdir_fid.Fid,
! 				tname,
! 				&OutDirStatus,
! 				&tsync);
! 		RX_AFS_GLOCK();
! 		XSTATS_END_TIME;
! 	   } else
! 		code = -1;
! 	} while (afs_Analyze(tc,
! 			code,
! 			&pdir_fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_REMOVEDIR,
! 			SHARED_LOCK,
! 			NULL));
! 
!     }				/* if (vType(avc) == VREG) */
! 
!     if (code)
!     	printf("afs_ProcessOpRemove: server returned code=%u\n", code);
! 
!     /* Remove the statd flag from parent dir's vcache. */
!     ObtainSharedLock(&afs_xvcache, 761);
!     tdp = afs_FindVCache(&pdir_fid, 0, 1);
!     ReleaseSharedLock(&afs_xvcache);
!     if (tdp) {
!     	ObtainWriteLock(&tdp->lock, 746);
! 	tdp->states &= ~CStatd;
! 	ReleaseWriteLock(&tdp->lock);
! 	afs_PutVCache(tdp);
!     }
! end:
!     afs_osi_Free(tname, AFSNAMEMAX);
!     return code;
! }
! 
! /*!
!  * Send disconnected file changes to the server.
!  *
!  * \note Call with vnode locked both locally and on the server.
!  *
!  * \param avc Vnode that gets synchronized to the server.
!  * \param areq Used for obtaining a conn struct.
!  *
!  * \return 0 for success. On failure, other error codes.
!  */
! int afs_SendChanges(struct vcache *avc, struct vrequest *areq)
! {
!     struct conn *tc;
!     struct AFSStoreStatus sstat;
!     struct AFSFetchStatus fstat;
!     struct AFSVolSync tsync;
!     int code = 0;
!     int flags = 0;
!     XSTATS_DECLS;
! 
!     /* Start multiplexing dirty operations from ddirty_flags field: */
!     if (avc->ddirty_flags & VDisconSetAttrMask) {
! 	/* Setattr OPS: */
! 	/* Turn dirty vc data into a new store status... */
! 	if (afs_GenStoreStatus(avc, &sstat) > 0) {
! 	    do {
! 		tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
! 		if (tc) {
! 		    /* ... and send it. */
! 		    XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STORESTATUS);
! 		    RX_AFS_GUNLOCK();
! 		    code = RXAFS_StoreStatus(tc->id,
! 				(struct AFSFid *) &avc->fid.Fid,
! 				&sstat,
! 				&fstat,
! 				&tsync);
! 
! 		    RX_AFS_GLOCK();
! 		    XSTATS_END_TIME;
! 		} else
! 		    code = -1;
! 
! 	} while (afs_Analyze(tc,
! 			code,
! 			&avc->fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_STORESTATUS,
! 			SHARED_LOCK,
! 			NULL));
! 
! 	}		/* if (afs_GenStoreStatus() > 0)*/
!     }			/* disconnected SETATTR */
! 
!     if (code)
!     	return code;
! 
!     if (avc->ddirty_flags &
! 	(VDisconTrunc
! 	| VDisconWriteClose
! 	| VDisconWriteFlush
! 	| VDisconWriteOsiFlush)) {
! 
! 	/* Truncate OP: */
! 	do {
! 	    tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
! 	    if (tc) {
! 		/* Set storing flags. XXX: A tad inefficient ... */
! 		if (avc->ddirty_flags & VDisconWriteClose)
! 		    flags |= AFS_LASTSTORE;
! 		if (avc->ddirty_flags & VDisconWriteOsiFlush)
! 		    flags |= (AFS_SYNC | AFS_LASTSTORE);
! 		if (avc->ddirty_flags & VDisconWriteFlush)
! 		    flags |= AFS_SYNC;
! 
! 		/* Try to send store to server. */
! 		/* XXX: AFS_LASTSTORE for writes? Or just AFS_SYNC for all? */
! 		code = afs_StoreAllSegments(avc, areq, flags);
! 	    } else
! 		code = -1;
! 
! 	} while (afs_Analyze(tc,
! 			code,
! 			&avc->fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_STOREDATA,
! 			SHARED_LOCK,
! 			NULL));
! 
!     }			/* disconnected TRUNC | WRITE */
! 
!     return code;
! }
! 
! /*!
!  * All files that have been dirty before disconnection are going to
!  * be replayed back to the server.
!  *
!  * \param areq Request from the user.
!  * \param acred User credentials.
!  *
!  * \return If all files synchronized succesfully, return 0, otherwise
!  * return 1.
!  *
!  * \note For now, it's the request from the PDiscon pioctl.
!  *
!  */
! int afs_ResyncDisconFiles(struct vrequest *areq, struct AFS_UCRED *acred)
! {
!     struct conn *tc;
!     struct vcache *tvc, *tmp;
!     struct AFSFetchStatus fstat;
!     struct AFSCallBack callback;
!     struct AFSVolSync tsync;
!     struct vcache *shList, *shListStart;
!     int code;
!     int sync_failed = 0;
!     int ret_code = 0;
!     int defered = 0;
!     afs_int32 start = 0;
!     XSTATS_DECLS;
!     //AFS_STATCNT(afs_ResyncDisconFiles);
! 
!     shList = shListStart = NULL;
! 
!     ObtainReadLock(&afs_DDirtyVCListLock);
! 
!     tvc = afs_DDirtyVCListStart;
!     while (tvc) {
! 
! 	/* Get local write lock. */
! 	ObtainWriteLock(&tvc->lock, 704);
!   	sync_failed = 0;
! 
! 	if ((tvc->ddirty_flags & VDisconRemove) &&
! 	    (tvc->ddirty_flags & VDisconCreate)) {
! 	   /* Data created and deleted locally. The server doesn't
! 	    * need to know about this, so we'll just skip this file
! 	    * from the dirty list.
! 	    */
! 	    goto skip_file;
! 
! 	} else if (tvc->ddirty_flags & VDisconRemove) {
! 	    /* Delete the file on the server and just move on
! 	     * to the next file. After all, it has been deleted
! 	     * we can't replay any other operation it.
! 	     */
! 	    code = afs_ProcessOpRemove(tvc, areq);
! 	    if (code == ENOTEMPTY)
! 	    	defered = 1;
! 	    goto skip_file;
! 
! 	} else if (tvc->ddirty_flags & VDisconCreate) {
! 	    /* For newly created files, we don't need a server lock. */
! 	    code = afs_ProcessOpCreate(tvc, areq, acred);
! 	    if (code == ENOTEMPTY)
! 	    	defered = 1;
! 	    if (code)
! 	    	goto skip_file;
! 	}
! 
!   	/* Get server write lock. */
!   	do {
! 	    tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
!   	    if (tc) {
! 	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
!   		RX_AFS_GUNLOCK();
!   		code = RXAFS_SetLock(tc->id,
! 					(struct AFSFid *)&tvc->fid.Fid,
! 					LockWrite,
! 					&tsync);
! 		RX_AFS_GLOCK();
! 		XSTATS_END_TIME;
! 	   } else
! 		code = -1;
! 
! 	} while (afs_Analyze(tc,
! 			code,
! 			&tvc->fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_SETLOCK,
! 			SHARED_LOCK,
! 			NULL));
! 
! 	if (code) {
! 	    sync_failed = 1;
! 	    goto skip_file;
! 	}
! 
! 	if ((tvc->ddirty_flags & VDisconRename) &&
! 		!(tvc->ddirty_flags & VDisconCreate)) {
! 	    /* Rename file only if it hasn't been created locally. */
! 	    code = afs_ProcessOpRename(tvc, areq);
! 	    if (code)
! 	    	goto skip_file;
! 	}
! 
! 	/* Issue a FetchStatus to get info about DV and callbacks. */
! 	do {
! 	    tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
! 	    if (tc) {
! 	    	tvc->callback = tc->srvr->server;
! 		start = osi_Time();
! 		XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
! 		RX_AFS_GUNLOCK();
! 		code = RXAFS_FetchStatus(tc->id,
! 				(struct AFSFid *)&tvc->fid.Fid,
! 				&fstat,
! 				&callback,
! 				&tsync);
! 		RX_AFS_GLOCK();
! 		XSTATS_END_TIME;
! 	    } else
! 		code = -1;
! 
! 	} while (afs_Analyze(tc,
! 			code,
! 			&tvc->fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_FETCHSTATUS,
! 			SHARED_LOCK,
! 			NULL));
! 
! 	if (code) {
! 	    sync_failed = 1;
! 	    goto unlock_srv_file;
! 	}
! 
! 	if ((dv_match(tvc, fstat) && (tvc->m.Date == fstat.ServerModTime)) ||
! 	    	(afs_ConflictPolicy == CLIENT_WINS) ||
! 		(tvc->ddirty_flags & VDisconCreate)) {
! 	    /*
! 	     * Send changes to the server if there's data version match, or
! 	     * client wins policy has been selected or file has been created
! 	     * but doesn't have it's the contents on to the server yet.
! 	     */
! 	   /*
! 	    * XXX: Checking server attr changes by timestamp might not the
! 	    * most elegant solution, but it's the most viable one that we could find.
! 	    */
! 	    afs_UpdateStatus(tvc, &tvc->fid, areq, &fstat, &callback, start);
! 	    code = afs_SendChanges(tvc, areq);
! 
! 	} else if (afs_ConflictPolicy == SERVER_WINS) {
! 	    /* DV mismatch, apply collision resolution policy. */
! 	    /* Dequeue whatever callback is on top (XXX: propably none). */
!       	    ObtainWriteLock(&afs_xcbhash, 706);
! 	    afs_DequeueCallback(tvc);
! 	    tvc->callback = NULL;
! 	    tvc->states &= ~(CStatd | CDirty | CUnique);
! 	    ReleaseWriteLock(&afs_xcbhash);
! 
! 	    /* Save metadata. File length gets updated as well because we
! 	     * just removed CDirty from the avc.
! 	     */
! 	    //afs_ProcessFS(tvc, &fstat, areq);
! 
! 	    /* Discard this files chunks and remove from current dir. */
! 	    afs_TryToSmush(tvc, acred, 1);
! 	    osi_dnlc_purgedp(tvc);
! 	    if (tvc->linkData && !(tvc->states & CCore)) {
! 		/* Take care of symlinks. */
! 		afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
! 		tvc->linkData = NULL;
! 	    }
! 
! 	    /* Otherwise file content's won't be synchronized. */
! 	    tvc->truncPos = AFS_NOTRUNC;
! 
! 	} else {
! 	    printf("afs_ResyncDisconFiles: no resolution policy selected.\n");
! 	}		/* if DV match or client wins policy */
! 
! 	if (code) {
! 	    sync_failed = 1;
! 	    printf("Sync FAILED.\n");
! 	}
! 
! unlock_srv_file:
! 	/* Release server write lock. */
! 	do {
! 	    tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
! 	    if (tc) {
! 	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
! 	    	RX_AFS_GUNLOCK();
! 		code = RXAFS_ReleaseLock(tc->id,
! 				(struct AFSFid *) &tvc->fid.Fid,
! 				&tsync);
! 		RX_AFS_GLOCK();
! 		XSTATS_END_TIME;
! 	    } else
! 		code = -1;
! 	} while (afs_Analyze(tc,
! 			code,
! 			&tvc->fid,
! 			areq,
! 			AFS_STATS_FS_RPCIDX_RELEASELOCK,
! 			SHARED_LOCK,
! 			NULL));
! 
! skip_file:
! 	/* Pop this dirty vc out. */
! 	tmp = tvc;
! 	tvc = tvc->ddirty_next;
! 
! 	if (!defered) {
! 	    /* Vnode not deferred. Clean it up. */
! 	    if (!sync_failed) {
! 	    	if (tmp->ddirty_flags == VDisconShadowed) {
! 		    /* Dirs that have only the shadow flag set might still
! 		     * be used so keep them in a different list, that gets
! 		     * deleted after resync is done.
! 		     */
! 		    if (!shListStart)
! 		    	shListStart = shList = tmp;
! 		    else {
! 		    	shList->ddirty_next = tmp;
! 			shList = tmp;
! 		    }
! 		} else if (tmp->ddirty_flags & VDisconShadowed)
! 	    	    /* We can discard the shadow dir now. */
! 	    	    afs_DeleteShadowDir(tmp);
! 
! 		if (tmp->ddirty_flags & VDisconRemove)
! 		    /* Drop the refcount on the deleted vnodes,
! 		     * because we don't need them anymore.
! 		     */
! 		    afs_PutVCache(tmp);
! 
! 	    	/* Only if sync was successfull,
! 		 * clear flags and dirty references.
! 		 */
! 	    	tmp->ddirty_next = NULL;
! 	    	tmp->ddirty_flags = 0;
! 	    } else
! 	    	ret_code = 1;
! 	} else {
! 	    tmp->ddirty_next = NULL;
! 	    defered = 0;
! 	}			/* if (!defered) */
! 
! 	/* Release local write lock. */
! 	ReleaseWriteLock(&tmp->lock);
!     }			/* while (tvc) */
! 
!     /* Delete the rest of shadow dirs. */
!     tvc = shListStart;
!     while (tvc) {
!     	ObtainWriteLock(&tvc->lock, 764);
! 
! 	afs_DeleteShadowDir(tvc);
! 	tvc->shVnode = 0;
! 	tvc->shUnique = 0;
! 
! 	tmp = tvc;
! 	tvc = tvc->ddirty_next;
! 	tmp->ddirty_next = NULL;
! 
! 	ReleaseWriteLock(&tmp->lock);
!     }				/* while (tvc) */
! 
!     if (ret_code == 0) {
!     	/* NULLIFY dirty list only if resync complete. */
! 	afs_DDirtyVCListStart = NULL;
! 	afs_DDirtyVCList = NULL;
!     }
!     ReleaseReadLock(&afs_DDirtyVCListLock);
! 
!     return ret_code;
! }
! 
! /*!
!  * Print list of disconnected files.
!  *
!  * \note Call with afs_DDirtyVCListLock read locked.
!  */
! void afs_DbgDisconFiles()
! {
!     struct vcache *tvc;
!     int i = 0;
! 
!     tvc = afs_DDirtyVCListStart;
!     printf("List of dirty files: \n");
!     while (tvc) {
! 	printf("Cell=%u Volume=%u VNode=%u Unique=%u\n",
! 		tvc->fid.Cell,
! 		tvc->fid.Fid.Volume,
! 		tvc->fid.Fid.Vnode,
! 		tvc->fid.Fid.Unique);
! 	tvc = tvc->ddirty_next;
! 	i++;
! 	if (i >= 30)
! 	    osi_Panic("afs_DbgDisconFiles: loop in dirty list\n");
!     }
! }
! 
! /*!
!  * Generate a fake fid for a disconnected shadow dir.
!  * Similar to afs_GenFakeFid, only that it uses the dhash
!  * to search for a uniquifier because a shadow dir lives only
!  * in the dcache.
!  *
!  * \param afid
!  *
!  * \note Don't forget to fill in afid with Cell and Volume.
!  */
! void afs_GenShadowFid(struct VenusFid *afid)
! {
!     afs_uint32 i, index, max_unique = 1;
!     struct vcache *tvc = NULL;
! 
!     /* Try generating a fid that isn't used in the vhash. */
!     do {
!     	afid->Fid.Vnode = afs_DisconVnode + 1;
! 
!     	i = DVHash(afid);
!     	ObtainWriteLock(&afs_xdcache, 737);
!     	for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
!             i = afs_dvnextTbl[index];
!             if (afs_indexUnique[index] > max_unique)
! 	    	max_unique = afs_indexUnique[index];
!     	}
! 
! 	ReleaseWriteLock(&afs_xdcache);
! 	afid->Fid.Unique = max_unique + 1;
! 	afs_DisconVnode += 2;
! 	if (!afs_DisconVnode)
!     	    afs_DisconVnode = 2;
! 
! 	/* Is this a used vnode? */
!     	ObtainSharedLock(&afs_xvcache, 762);
!     	tvc = afs_FindVCache(afid, 0, 1);
!     	ReleaseSharedLock(&afs_xvcache);
! 	if (tvc)
! 	    afs_PutVCache(tvc);
!     } while (tvc);
! }
! 
! /*!
!  * Generate a fake fid (vnode and uniquifier) for a vcache
!  * (either dir or normal file). The vnode is generated via
!  * afs_DisconVNode and the uniquifier by getting the highest
!  * uniquifier on a hash chain and incrementing it by one.
!  *
!  * \param avc afid The fid structre that will be filled.
!  * \param avtype Vnode type: VDIR/VREG.
!  *
!  * \note The cell number must be completed somewhere else.
!  */
! void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype)
! {
!     struct vcache *tvc;
!     afs_uint32 max_unique = 1, i;
! 
!     if (avtype == VDIR)
!     	afid->Fid.Vnode = afs_DisconVnode + 1;
!     else if (avtype == VREG)
!     	afid->Fid.Vnode = afs_DisconVnode;
! 
!     ObtainWriteLock(&afs_xvcache, 736);
!     i = VCHash(afid);
!     for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
!         if (tvc->fid.Fid.Unique > max_unique)
! 	    max_unique = tvc->fid.Fid.Unique;
!     }
!     ReleaseWriteLock(&afs_xvcache);
! 
!     afid->Fid.Unique = max_unique + 1;
!     afs_DisconVnode += 2;
!     if (!afs_DisconVnode)
!     	afs_DisconVnode = 2;
! }
! 
! /*!
!  * Fill in stats for a newly created file/directory.
!  *
!  * \param adp The parent dir's vcache.
!  * \param avc The created vnode.
!  * \param afid The new fid.
!  * \param attrs
!  * \param areq
!  * \param file_type Specify if file or directory.
!  *
!  * \note Call with avc write locked.
!  */
! void afs_GenDisconStatus(
!         struct vcache *adp,
!         struct vcache *avc,
! 	struct VenusFid *afid,
!         struct vattr *attrs,
!         struct vrequest *areq,
!         int file_type)
! {
!     memcpy(&avc->fid, afid, sizeof(struct VenusFid));
!     avc->m.Mode = attrs->va_mode;
!     /* Used to do this:
!      * avc->m.Owner = attrs->va_uid;
!      * But now we use the parent dir's ownership,
!      * there's no other way to get a server owner id.
!      * XXX: Does it really matter?
!      */
!     avc->m.Group = adp->m.Group;
!     avc->m.Owner = adp->m.Owner;
!     hset64(avc->m.DataVersion, 0, 0);
!     avc->m.Length = attrs->va_size;
!     avc->m.Date = osi_Time();
!     if (file_type == VREG) {
!         vSetType(avc, VREG);
!         avc->m.Mode |= S_IFREG;
! 	avc->m.LinkCount = 1;
!     } else if (file_type == VDIR) {
!         vSetType(avc, VDIR);
!         avc->m.Mode |= S_IFDIR;
! 	avc->m.LinkCount = 2;
!     }
! 
!     avc->anyAccess = adp->anyAccess;
!     afs_AddAxs(avc->Access, areq->uid, adp->Access->axess);
! 
!     avc->callback = NULL;
!     avc->states |= CStatd;
!     avc->states &= ~CBulkFetching;
! }
  #endif
Index: openafs/src/afs/afs_init.c
diff -c openafs/src/afs/afs_init.c:1.37.4.7 openafs/src/afs/afs_init.c:1.37.4.8
*** openafs/src/afs/afs_init.c:1.37.4.7	Thu Jun 12 13:24:38 2008
--- openafs/src/afs/afs_init.c	Mon Sep 22 15:29:54 2008
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_init.c,v 1.37.4.7 2008/06/12 17:24:38 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
--- 17,23 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_init.c,v 1.37.4.8 2008/09/22 19:29:54 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
***************
*** 47,52 ****
--- 47,53 ----
  #endif
  #if defined(AFS_DISCON_ENV)
  afs_rwlock_t afs_discon_lock;
+ extern afs_rwlock_t afs_DDirtyVCListLock;
  #endif
  
  /*
***************
*** 115,120 ****
--- 116,122 ----
      RWLOCK_INIT(&afs_xaxs, "afs_xaxs");
  #ifdef AFS_DISCON_ENV
      RWLOCK_INIT(&afs_discon_lock, "afs_discon_lock");
+     RWLOCK_INIT(&afs_DDirtyVCListLock, "afs_DDirtyVCListLock");
  #endif
      osi_dnlc_init();
  
Index: openafs/src/afs/afs_osi.c
diff -c openafs/src/afs/afs_osi.c:1.58.2.6 openafs/src/afs/afs_osi.c:1.58.2.7
*** openafs/src/afs/afs_osi.c:1.58.2.6	Tue Feb  5 20:32:13 2008
--- openafs/src/afs/afs_osi.c	Tue Aug 26 10:01:31 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi.c,v 1.58.2.6 2008/02/06 01:32:13 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi.c,v 1.58.2.7 2008/08/26 14:01:31 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 91,96 ****
--- 91,101 ----
      usimple_lock_init(&afs_global_lock);
      afs_global_owner = (thread_t) 0;
  #elif defined(AFS_FBSD50_ENV)
+ #if defined(AFS_FBSD80_ENV) && defined(WITNESS)
+     /* "lock_initalized" (sic) can panic, checks a flag bit
+      * is unset _before_ init */
+     memset(&afs_global_mtx, 0, sizeof(struct mtx));
+ #endif
      mtx_init(&afs_global_mtx, "AFS global lock", NULL, MTX_DEF);
  #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
  #if !defined(AFS_DARWIN80_ENV)
Index: openafs/src/afs/afs_osi_alloc.c
diff -c openafs/src/afs/afs_osi_alloc.c:1.11.6.6 openafs/src/afs/afs_osi_alloc.c:1.11.6.7
*** openafs/src/afs/afs_osi_alloc.c:1.11.6.6	Tue May 20 15:50:41 2008
--- openafs/src/afs/afs_osi_alloc.c	Tue Aug 26 10:01:31 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_alloc.c,v 1.11.6.6 2008/05/20 19:50:41 shadow Exp $");
  
  
  
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_alloc.c,v 1.11.6.7 2008/08/26 14:01:31 shadow Exp $");
  
  
  
***************
*** 19,25 ****
  #include "afsincludes.h"	/* Afs-based standard headers */
  #include "afs/afs_stats.h"	/* afs statistics */
  
! #ifndef AFS_FBSD_ENV
  
  #ifdef AFS_AIX41_ENV
  #include "sys/lockl.h"
--- 19,25 ----
  #include "afsincludes.h"	/* Afs-based standard headers */
  #include "afs/afs_stats.h"	/* afs statistics */
  
! 
  
  #ifdef AFS_AIX41_ENV
  #include "sys/lockl.h"
***************
*** 257,260 ****
  		 afs_stats_cmperf.SmallBlocksActive);
      }
  }
! #endif
--- 257,260 ----
  		 afs_stats_cmperf.SmallBlocksActive);
      }
  }
! 
Index: openafs/src/afs/afs_osi_vm.c
diff -c openafs/src/afs/afs_osi_vm.c:1.1.2.2 openafs/src/afs/afs_osi_vm.c:1.1.2.4
*** openafs/src/afs/afs_osi_vm.c:1.1.2.2	Mon Jul 31 17:27:38 2006
--- openafs/src/afs/afs_osi_vm.c	Mon Sep 22 15:35:26 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_vm.c,v 1.1.2.2 2006/07/31 21:27:38 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_vm.c,v 1.1.2.4 2008/09/22 19:35:26 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 49,55 ****
--- 49,66 ----
  void
  osi_FlushPages(register struct vcache *avc, struct AFS_UCRED *credp)
  {
+     int vfslocked;
      afs_hyper_t origDV;
+ #if defined(AFS_CACHE_BYPASS)
+     /* The optimization to check DV under read lock below is identical a 
+      * change in CITI cache bypass work.  The problem CITI found in 1999 
+      * was that this code and background daemon doing prefetching competed 
+      * for the vcache entry shared lock.  It's not clear to me from the 
+      * tech report, but it looks like CITI fixed the general prefetch code
+      * path as a bonus when experimenting on prefetch for cache bypass, see
+      * citi-tr-01-3.
+      */
+ #endif        
      ObtainReadLock(&avc->lock);
      /* If we've already purged this version, or if we're the ones
       * writing this version, don't flush it (could lose the
***************
*** 79,87 ****
--- 90,108 ----
  	       ICL_TYPE_INT32, origDV.low, ICL_TYPE_INT32, avc->m.Length);
  
      ReleaseWriteLock(&avc->lock);
+ #ifdef AFS_FBSD70_ENV
+     vfslocked = VFS_LOCK_GIANT(AFSTOV(avc)->v_mount);
+ #endif
+ #ifndef AFS_FBSD70_ENV
      AFS_GUNLOCK();
+ #endif
      osi_VM_FlushPages(avc, credp);
+ #ifndef AFS_FBSD70_ENV
      AFS_GLOCK();
+ #endif
+ #ifdef AFS_FBSD70_ENV
+     VFS_UNLOCK_GIANT(vfslocked);
+ #endif
      ObtainWriteLock(&avc->lock, 88);
  
      /* do this last, and to original version, since stores may occur
Index: openafs/src/afs/afs_osidnlc.c
diff -c openafs/src/afs/afs_osidnlc.c:1.13.2.1 openafs/src/afs/afs_osidnlc.c:1.13.2.2
*** openafs/src/afs/afs_osidnlc.c:1.13.2.1	Fri Oct 19 16:39:07 2007
--- openafs/src/afs/afs_osidnlc.c	Tue Aug 26 10:01:31 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osidnlc.c,v 1.13.2.1 2007/10/19 20:39:07 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osidnlc.c,v 1.13.2.2 2008/08/26 14:01:31 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 63,68 ****
--- 63,76 ----
  
  #define dnlcHash(ts, hval) for (hval=0; *ts; ts++) { hval *= 173;  hval  += *ts;   }
  
+ #if defined(AFS_FBSD80_ENV) && !defined(UKERNEL)
+ #define ma_critical_enter critical_enter
+ #define ma_critical_exit critical_exit
+ #else
+ #define ma_critical_enter() {}
+ #define ma_critical_exit() {}
+ #endif
+ 
  static struct nc *
  GetMeAnEntry(void)
  {
***************
*** 201,212 ****
      vnode_t tvp;
  #endif
  
!     if (!afs_usednlc)
! 	return 0;
  
      dnlcHash(ts, key);		/* leaves ts pointing at the NULL */
      if (ts - aname >= AFSNCNAMESIZE) {
! 	return 0;
      }
      skey = key & (NHSIZE - 1);
  
--- 209,225 ----
      vnode_t tvp;
  #endif
  
!     ma_critical_enter();
! 
!     if (!afs_usednlc) {
!       ma_critical_exit();
!       return 0;
!     }
  
      dnlcHash(ts, key);		/* leaves ts pointing at the NULL */
      if (ts - aname >= AFSNCNAMESIZE) {
!       ma_critical_exit();
!       return 0;
      }
      skey = key & (NHSIZE - 1);
  
***************
*** 231,236 ****
--- 244,250 ----
  	    ReleaseReadLock(&afs_xdnlc);
  	    ReleaseReadLock(&afs_xvcache);
  	    osi_dnlc_purge();
+ 	    ma_critical_exit();
  	    return (0);
  	}
      }
***************
*** 251,256 ****
--- 265,271 ----
  	    ReleaseReadLock(&afs_xvcache);
  	    dnlcstats.misses++;
  	    osi_dnlc_remove(adp, aname, tvc);
+ 	    ma_critical_exit();
  	    return 0;
  	}
  #ifdef	AFS_OSF_ENV
***************
*** 262,267 ****
--- 277,283 ----
  	    ReleaseReadLock(&afs_xvcache);
  	    dnlcstats.misses++;
  	    osi_dnlc_remove(adp, aname, tvc);
+ 	    ma_critical_exit();
  	    return 0;
  	}
  	if (vnode_ref(tvp)) {
***************
*** 271,280 ****
--- 287,304 ----
  	    AFS_GLOCK();
  	    dnlcstats.misses++;
  	    osi_dnlc_remove(adp, aname, tvc);
+ 	    ma_critical_exit();
  	    return 0;
  	}
  #else
+ #ifdef AFS_FBSD50_ENV
+ 	/* can't sleep in a critical section */
+ 	ma_critical_exit();
+ 	osi_vnhold(tvc, 0);
+ 	ma_critical_enter();
+ #else
  	osi_vnhold(tvc, 0);
+ #endif /* AFS_FBSD80_ENV */
  #endif
  #endif
  	ReleaseReadLock(&afs_xvcache);
***************
*** 313,318 ****
--- 337,343 ----
  #endif
      }
  
+     ma_critical_exit();
      return tvc;
  }
  
Index: openafs/src/afs/afs_pioctl.c
diff -c openafs/src/afs/afs_pioctl.c:1.110.2.18 openafs/src/afs/afs_pioctl.c:1.110.2.20
*** openafs/src/afs/afs_pioctl.c:1.110.2.18	Fri May 23 10:25:15 2008
--- openafs/src/afs/afs_pioctl.c	Mon Sep 22 15:35:26 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_pioctl.c,v 1.110.2.18 2008/05/23 14:25:15 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #ifdef AFS_OBSD_ENV
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_pioctl.c,v 1.110.2.20 2008/09/22 19:35:26 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #ifdef AFS_OBSD_ENV
***************
*** 23,28 ****
--- 23,29 ----
  #include "afsincludes.h"	/* Afs-based standard headers */
  #include "afs/afs_stats.h"	/* afs statistics */
  #include "afs/vice.h"
+ #include "afs/afs_bypasscache.h"
  #include "rx/rx_globals.h"
  
  struct VenusFid afs_rootFid;
***************
*** 33,38 ****
--- 34,44 ----
  #ifdef AFS_DISCON_ENV
  afs_int32 afs_is_disconnected;
  afs_int32 afs_is_logging;
+ afs_int32 afs_is_discon_rw;
+ /* On reconnection, turn this knob on until it finishes,
+  * then turn it off.
+  */
+ afs_int32 afs_in_sync = 0;
  #endif
  
  #define DECL_PIOCTL(x) static int x(struct vcache *avc, int afun, struct vrequest *areq, \
***************
*** 99,104 ****
--- 105,114 ----
  DECL_PIOCTL(PNFSNukeCreds);
  DECL_PIOCTL(PNewUuid);
  DECL_PIOCTL(PPrecache); 
+ #if defined(AFS_CACHE_BYPASS)
+ DECL_PIOCTL(PSetCachingThreshold);
+ DECL_PIOCTL(PSetCachingBlkSize);
+ #endif
  
  /*
   * A macro that says whether we're going to need HandleClientContext().
***************
*** 214,220 ****
  
  static int (*(OpioctlSw[])) () = {
      PBogus,			/* 0 */
! 	PNFSNukeCreds,		/* 1 -- nuke all creds for NFS client */
  };
  
  #define PSetClientContext 99	/*  Special pioctl to setup caller's creds  */
--- 224,235 ----
  
  static int (*(OpioctlSw[])) () = {
      PBogus,			/* 0 */
!     PNFSNukeCreds,		/* 1 -- nuke all creds for NFS client */
! #if defined(AFS_CACHE_BYPASS)
!     PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
! #else
!     PNoop                       /* 2 -- get/set cache-bypass size threshold */
! #endif
  };
  
  #define PSetClientContext 99	/*  Special pioctl to setup caller's creds  */
***************
*** 3875,3880 ****
--- 3890,3940 ----
      return 0;
  }
  
+ #if defined(AFS_CACHE_BYPASS)
+ 
+ DECL_PIOCTL(PSetCachingThreshold)
+ {
+     afs_int32 getting;
+     afs_int32 setting;
+ 
+     setting = getting = 1;
+ 
+     if (ain == NULL || ainSize < sizeof(afs_int32))
+ 	setting = 0;
+ 
+     if (aout == NULL)
+ 	getting = 0;
+ 
+     if (setting == 0 && getting == 0)
+ 	return EINVAL;
+ 	
+     /* 
+      * If setting, set first, and return the value now in effect
+      */
+     if (setting) {
+ 	afs_int32 threshold;
+ 
+ 	if (!afs_osi_suser(*acred))
+ 	    return EPERM;
+ 	memcpy((char *)&threshold, ain, sizeof(afs_int32));
+ 	cache_bypass_threshold = threshold;
+         afs_warn("Cache Bypass Threshold set to: %d\n", threshold);		
+ 	/* TODO:  move to separate pioctl, or enhance pioctl */
+ 	cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
+     }
+ 	
+     if (getting) {
+ 	/* Return the current size threshold */
+ 	afs_int32 oldThreshold = cache_bypass_threshold;
+ 	memcpy(aout, (char *)&oldThreshold, sizeof(afs_int32));
+ 	*aoutSize = sizeof(afs_int32);
+     }
+ 
+     return(0);
+ }
+ 
+ #endif /* defined(AFS_CACHE_BYPASS) */
+ 
  DECL_PIOCTL(PCallBackAddr)
  {
  #ifndef UKERNEL
***************
*** 3976,4007 ****
  DECL_PIOCTL(PDiscon)
  {
  #ifdef AFS_DISCON_ENV
!     static afs_int32 mode = 4; /* Start up in 'full' */
  
!     if (ainSize == sizeof(afs_int32)) {
  
  	if (!afs_osi_suser(*acred))
  	    return EPERM;
  
! 	memcpy(&mode, ain, sizeof(afs_int32));
  
  	/*
  	 * All of these numbers are hard coded in fs.c. If they
  	 * change here, they should change there and vice versa
  	 */
  	switch (mode) {
! 	case 0: /* Disconnect, breaking all callbacks */
  	    if (!AFS_IS_DISCONNECTED) {
  		ObtainWriteLock(&afs_discon_lock, 999);
  		afs_DisconGiveUpCallbacks();
  		afs_RemoveAllConns();
  		afs_is_disconnected = 1;
  		ReleaseWriteLock(&afs_discon_lock);
  	    }
  	    break;
! 	case 4: /* Fully connected */
  	    ObtainWriteLock(&afs_discon_lock, 998);
! 	    afs_is_disconnected = 0;
  	    ReleaseWriteLock(&afs_discon_lock);
  	    break;
  	default:
--- 4036,4088 ----
  DECL_PIOCTL(PDiscon)
  {
  #ifdef AFS_DISCON_ENV
!     static afs_int32 mode = 1; /* Start up in 'off' */
!     afs_int32 force = 0;
!     int code = 0;
  
!     if (ainSize) {
  
  	if (!afs_osi_suser(*acred))
  	    return EPERM;
  
! 	if (ain[0])
! 	    mode = ain[0] - 1;
! 	if (ain[1])
! 	    afs_ConflictPolicy = ain[1] - 1;
! 	if (ain[2])
! 	    force = 1;
  
  	/*
  	 * All of these numbers are hard coded in fs.c. If they
  	 * change here, they should change there and vice versa
  	 */
  	switch (mode) {
! 	case 0: /* Disconnect ("offline" mode), breaking all callbacks */
  	    if (!AFS_IS_DISCONNECTED) {
  		ObtainWriteLock(&afs_discon_lock, 999);
  		afs_DisconGiveUpCallbacks();
  		afs_RemoveAllConns();
  		afs_is_disconnected = 1;
+ 		afs_is_discon_rw = 1;
  		ReleaseWriteLock(&afs_discon_lock);
  	    }
  	    break;
! 	case 1: /* Fully connected, ("online" mode). */
  	    ObtainWriteLock(&afs_discon_lock, 998);
! 
! 	    afs_in_sync = 1;
! 	    code = afs_ResyncDisconFiles(areq, *acred);
! 	    afs_in_sync = 0;
! 
! 	    if (code && !force) {
! 	    	printf("Files not synchronized properly, still in discon state. \
! 						Please retry or use \"force\".\n");
! 	    } else {
! 		afs_is_disconnected = 0;
! 		afs_is_discon_rw = 0;
! 		printf("\nSync succeeded. You are back online.\n");
! 	    }
! 
  	    ReleaseWriteLock(&afs_discon_lock);
  	    break;
  	default:
Index: openafs/src/afs/afs_prototypes.h
diff -c openafs/src/afs/afs_prototypes.h:1.74.2.17 openafs/src/afs/afs_prototypes.h:1.74.2.18
*** openafs/src/afs/afs_prototypes.h:1.74.2.17	Fri Jul 18 10:54:34 2008
--- openafs/src/afs/afs_prototypes.h	Mon Sep 22 15:29:54 2008
***************
*** 255,261 ****
  extern void afs_CacheTruncateDaemon(void);
  extern void afs_AdjustSize(register struct dcache *adc,
  			   register afs_int32 newSize);
! extern int afs_HashOutDCache(struct dcache *adc);
  extern int afs_MaybeFreeDiscardedDCache(void);
  extern int afs_RefDCache(struct dcache *adc);
  extern void afs_TryToSmush(register struct vcache *avc,
--- 255,261 ----
  extern void afs_CacheTruncateDaemon(void);
  extern void afs_AdjustSize(register struct dcache *adc,
  			   register afs_int32 newSize);
! extern int afs_HashOutDCache(struct dcache *adc, int zap);
  extern int afs_MaybeFreeDiscardedDCache(void);
  extern int afs_RefDCache(struct dcache *adc);
  extern void afs_TryToSmush(register struct vcache *avc,
Index: openafs/src/afs/afs_segments.c
diff -c openafs/src/afs/afs_segments.c:1.22.8.2 openafs/src/afs/afs_segments.c:1.22.8.3
*** openafs/src/afs/afs_segments.c:1.22.8.2	Fri May 23 10:25:16 2008
--- openafs/src/afs/afs_segments.c	Mon Sep 22 15:29:54 2008
***************
*** 14,20 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_segments.c,v 1.22.8.2 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 14,20 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_segments.c,v 1.22.8.3 2008/09/22 19:29:54 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 215,221 ****
  #endif
  	    osi_VM_StoreAllSegments(avc);
      }
!     if (AFS_IS_DISCONNECTED) {
          if (!AFS_IS_LOGGING) {
              /* This will probably make someone sad ... */
  	    /*printf("Net down in afs_StoreSegments\n");*/
--- 215,221 ----
  #endif
  	    osi_VM_StoreAllSegments(avc);
      }
!     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
          if (!AFS_IS_LOGGING) {
              /* This will probably make someone sad ... */
  	    /*printf("Net down in afs_StoreSegments\n");*/
Index: openafs/src/afs/afs_stats.h
diff -c openafs/src/afs/afs_stats.h:1.14.6.1 openafs/src/afs/afs_stats.h:1.14.6.2
*** openafs/src/afs/afs_stats.h:1.14.6.1	Mon Mar 17 14:03:37 2008
--- openafs/src/afs/afs_stats.h	Mon Sep 22 15:35:26 2008
***************
*** 640,645 ****
--- 640,649 ----
      afs_int32 C_SRXAFSCB_GetCacheConfig;	/* afs_callback.c */
      afs_int32 C_SRXAFSCB_GetCE64;	/* afs_callback.c */
      afs_int32 C_SRXAFSCB_GetCellByNum;	/* afs_callback.c */
+ #if defined(AFS_CACHE_BYPASS)
+     afs_int32 C_BPrefetchNoCache;	/* afs_daemons.c */
+ 	afs_int32 C_afs_ReadNoCache;	/* osi_vnodeops.c */
+ #endif	
  };
  
  struct afs_CMMeanStats {
Index: openafs/src/afs/afs_vcache.c
diff -c openafs/src/afs/afs_vcache.c:1.114.2.9 openafs/src/afs/afs_vcache.c:1.114.2.12
*** openafs/src/afs/afs_vcache.c:1.114.2.9	Fri May 23 10:25:16 2008
--- openafs/src/afs/afs_vcache.c	Mon Sep 22 15:35:26 2008
***************
*** 19,24 ****
--- 19,25 ----
   * afs_FlushActiveVcaches
   * afs_VerifyVCache2
   * afs_WriteVCache
+  * afs_WriteVCacheDiscon
   * afs_SimpleVStat
   * afs_ProcessFS
   * TellALittleWhiteLie
***************
*** 26,31 ****
--- 27,33 ----
   * afs_GetVCache
   * afs_LookupVCache
   * afs_GetRootVCache
+  * afs_UpdateStatus
   * afs_FetchStatus
   * afs_StuffVcache
   * afs_PutVCache
***************
*** 39,45 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_vcache.c,v 1.114.2.9 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 41,47 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_vcache.c,v 1.114.2.12 2008/09/22 19:35:26 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 942,947 ****
--- 944,953 ----
      tvc->Access = NULL;
      tvc->callback = serverp;    /* to minimize chance that clear
  				 * request is lost */
+ #if defined(AFS_DISCON_ENV)
+     tvc->ddirty_next = NULL;
+     tvc->ddirty_flags = 0;
+ #endif
  
      i = VCHash(afid);
      j = VCHashV(afid);
***************
*** 1033,1038 ****
--- 1039,1050 ----
      tvc->vmh = tvc->segid = NULL;
      tvc->credp = NULL;
  #endif
+ 
+ #if defined(AFS_CACHE_BYPASS)
+     tvc->cachingStates = 0;
+     tvc->cachingTransitions = 0;
+ #endif
+ 
  #ifdef AFS_BOZONLOCK_ENV
  #if	defined(AFS_SUN5_ENV)
      rw_init(&tvc->rwlock, "vcache rwlock", RW_DEFAULT, NULL);
***************
*** 1122,1127 ****
--- 1134,1144 ----
      insmntque(tvc, afs_globalVFS);
  #endif /* AFS_OSF_ENV */
  #endif /* AFS_DUX40_ENV */
+ #ifdef AFS_FBSD70_ENV
+ #ifndef AFS_FBSD80_ENV /* yup.  they put it back. */
+     insmntque(AFSTOV(tvc), afs_globalVFS);
+ #endif
+ #endif
  #if defined(AFS_SGI_ENV)
      VN_SET_DPAGES(&(tvc->v), (struct pfdat *)NULL);
      osi_Assert((tvc->v.v_flag & VINACT) == 0);
***************
*** 1502,1508 ****
      AFS_STATCNT(afs_WriteVCache);
      afs_Trace2(afs_iclSetp, CM_TRACE_WVCACHE, ICL_TYPE_POINTER, avc,
  	       ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
- 
      do {
  	tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
  	if (tc) {
--- 1519,1524 ----
***************
*** 1542,1547 ****
--- 1558,1655 ----
      return code;
  
  }				/*afs_WriteVCache */
+ #if defined(AFS_DISCON_ENV)
+ 
+ /*!
+  * Store status info only locally, set the proper disconnection flags
+  * and add to dirty list.
+  *
+  * \param avc The vcache to be written locally.
+  * \param astatus Get attr fields from local store.
+  * \param attrs This one is only of the vs_size.
+  *
+  * \note Must be called with a shared lock on the vnode
+  */
+ int afs_WriteVCacheDiscon(register struct vcache *avc,
+ 				register struct AFSStoreStatus *astatus,
+ 				struct vattr *attrs)
+ {
+     afs_int32 code = 0;
+     afs_int32 flags = 0;
+ 
+     UpgradeSToWLock(&avc->lock, 700);
+ 
+     if (!astatus->Mask) {
+ 
+ 	return code;
+ 
+     } else {
+ 
+     	/* Set attributes. */
+     	if (astatus->Mask & AFS_SETMODTIME) {
+ 		avc->m.Date = astatus->ClientModTime;
+ 		flags |= VDisconSetTime;
+ 	}
+ 
+ 	if (astatus->Mask & AFS_SETOWNER) {
+ 		printf("Not allowed yet. \n");
+ 		//avc->m.Owner = astatus->Owner;
+ 	}
+ 
+ 	if (astatus->Mask & AFS_SETGROUP) {
+ 		printf("Not allowed yet. \n");
+ 		//avc->m.Group =  astatus->Group;
+ 	}
+ 
+ 	if (astatus->Mask & AFS_SETMODE) {
+ 		avc->m.Mode = astatus->UnixModeBits;
+ 
+ #if 0 	/* XXX: Leaving this out, so it doesn't mess up the file type flag.*/
+ 
+ 		if (vType(avc) == VREG) {
+ 			avc->m.Mode |= S_IFREG;
+ 		} else if (vType(avc) == VDIR) {
+ 			avc->m.Mode |= S_IFDIR;
+ 		} else if (vType(avc) == VLNK) {
+ 			avc->m.Mode |= S_IFLNK;
+ 			if ((avc->m.Mode & 0111) == 0)
+ 				avc->mvstat = 1;
+ 		}
+ #endif
+ 		flags |= VDisconSetMode;
+ 	 } 		/* if(astatus.Mask & AFS_SETMODE) */
+ 
+      } 			/* if (!astatus->Mask) */
+ 
+      if (attrs->va_size > 0) {
+      	/* XXX: Do I need more checks? */
+      	/* Truncation operation. */
+      	flags |= VDisconTrunc;
+      }
+ 
+     ObtainWriteLock(&afs_DDirtyVCListLock, 701);
+ 
+     if (flags) {
+     	/* Add to disconnected dirty list and set dirty flag.*/
+ 	if (!avc->ddirty_flags ||
+ 		(avc->ddirty_flags == VDisconShadowed)) {
+ 		/* Not in dirty list. */
+ 		AFS_DISCON_ADD_DIRTY(avc);
+ 	}
+ 
+ 	avc->ddirty_flags |= flags;
+     }
+ 
+     ReleaseWriteLock(&afs_DDirtyVCListLock);
+ 
+     /* XXX: How about the rest of the fields? */
+ 
+     ConvertWToSLock(&avc->lock);
+ 
+     return code;
+ }
+ 
+ #endif
  
  /*
   * afs_ProcessFS
***************
*** 1822,1827 ****
--- 1930,1949 ----
  	  ObtainWriteLock(&tvc->lock, 954);
  	if (!iheldthelock)
  	    VOP_UNLOCK(vp, LK_EXCLUSIVE, current_proc());
+ #elif defined(AFS_FBSD80_ENV)
+ 	iheldthelock = VOP_ISLOCKED(vp);
+ 	if (!iheldthelock) {
+ 	    /* nosleep/sleep lock order reversal */
+ 	    int glocked = ISAFS_GLOCK();
+ 	    if (glocked)
+ 		AFS_GUNLOCK();
+ 	    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ 	    if (glocked)
+ 		AFS_GLOCK();
+ 	}
+ 	vinvalbuf(vp, V_SAVE, curthread, PINOD, 0);
+ 	if (!iheldthelock)
+ 	    VOP_UNLOCK(vp, 0);
  #elif defined(AFS_FBSD60_ENV)
  	iheldthelock = VOP_ISLOCKED(vp, curthread);
  	if (!iheldthelock)
***************
*** 1899,1910 ****
  	    tvc->parentUnique = OutStatus.ParentUnique;
  	    code = 0;
  	} else {
! 	    /* If we've got here and we're disconnected, then we can go
! 	     * no further
! 	     */
  	    if (AFS_IS_DISCONNECTED) {
! 		code = ENETDOWN;
! 		/*printf("Network is down in afs_GetCache");*/
  	    } else
  	        code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
  
--- 2021,2043 ----
  	    tvc->parentUnique = OutStatus.ParentUnique;
  	    code = 0;
  	} else {
! 
  	    if (AFS_IS_DISCONNECTED) {
! 		if (AFS_IS_DISCON_RW) {
! 		    /* Seek the vnode manually. */
! 		    ObtainSharedLock(&afs_xvcache, 738);
! 		    avc = afs_FindVCache(afid, NULL, 1);
! 		    ReleaseSharedLock(&afs_xvcache);
! 
! 		    if (vType(avc) == VDIR)
! 		    	OutStatus.FileType = Directory;
! 
! 		    code = tvc?0:ENOENT;
! 		} else {
! 		    /* Nothing to do otherwise...*/
! 		    code = ENETDOWN;
! 		    printf("Network is down in afs_GetCache");
! 		}
  	    } else
  	        code = afs_FetchStatus(tvc, afid, areq, &OutStatus);
  
***************
*** 1996,2002 ****
      origCBs = afs_allCBs;	/* if anything changes, we don't have a cb */
      
      if (AFS_IS_DISCONNECTED) {
! 	/*printf("Network is down in afs_LookupVcache\n");*/
          code = ENETDOWN;
      } else 
          code =
--- 2129,2135 ----
      origCBs = afs_allCBs;	/* if anything changes, we don't have a cb */
      
      if (AFS_IS_DISCONNECTED) {
! 	printf("Network is down in afs_LookupVcache\n");
          code = ENETDOWN;
      } else 
          code =
***************
*** 2357,2362 ****
--- 2490,2556 ----
  }
  
  
+ /*!
+  * Update callback status and (sometimes) attributes of a vnode.
+  * Called after doing a fetch status RPC. Whilst disconnected, attributes
+  * shouldn't be written to the vcache here.
+  *
+  * \param avc
+  * \param afid
+  * \param areq
+  * \param Outsp Server status after rpc call.
+  * \param acb Callback for this vnode.
+  *
+  * \note The vcache must be write locked.
+  */
+ void
+ afs_UpdateStatus(struct vcache *avc,
+ 			struct VenusFid *afid,
+ 			struct vrequest *areq,
+ 			struct AFSFetchStatus *Outsp,
+ 			struct AFSCallBack *acb,
+ 			afs_uint32 start)
+ {
+     struct volume *volp;
+ 
+     if (!AFS_IN_SYNC)
+ 	/* Dont write status in vcache if resyncing after a disconnection. */
+ 	afs_ProcessFS(avc, Outsp, areq);
+ 
+     volp = afs_GetVolume(afid, areq, READ_LOCK);
+     ObtainWriteLock(&afs_xcbhash, 469);
+     avc->states |= CTruth;
+     if (avc->callback /* check for race */ ) {
+ 	if (acb->ExpirationTime != 0) {
+ 	    avc->cbExpires = acb->ExpirationTime + start;
+ 	    avc->states |= CStatd;
+ 	    avc->states &= ~CBulkFetching;
+ 	    afs_QueueCallback(avc, CBHash(acb->ExpirationTime), volp);
+     	} else if (avc->states & CRO) {
+ 	    /* ordinary callback on a read-only volume -- AFS 3.2 style */
+ 	    avc->cbExpires = 3600 + start;
+ 	    avc->states |= CStatd;
+ 	    avc->states &= ~CBulkFetching;
+ 	    afs_QueueCallback(avc, CBHash(3600), volp);
+     	} else {
+ 	    afs_DequeueCallback(avc);
+ 	    avc->callback = NULL;
+ 	    avc->states &= ~(CStatd | CUnique);
+ 	    if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
+ 	    	osi_dnlc_purgedp(avc);	/* if it (could be) a directory */
+     	}
+     } else {
+     	afs_DequeueCallback(avc);
+     	avc->callback = NULL;
+     	avc->states &= ~(CStatd | CUnique);
+     	if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
+ 	    osi_dnlc_purgedp(avc);	/* if it (could be) a directory */
+     }
+     ReleaseWriteLock(&afs_xcbhash);
+     if (volp)
+     	afs_PutVolume(volp, READ_LOCK);
+ 
+ }
  
  /*
   * must be called with avc write-locked
***************
*** 2372,2378 ****
      register struct conn *tc;
      struct AFSCallBack CallBack;
      struct AFSVolSync tsync;
-     struct volume *volp;
      XSTATS_DECLS;
      do {
  	tc = afs_Conn(afid, areq, SHARED_LOCK);
--- 2566,2571 ----
***************
*** 2396,2433 ****
  	      SHARED_LOCK, NULL));
  
      if (!code) {
! 	afs_ProcessFS(avc, Outsp, areq);
! 	volp = afs_GetVolume(afid, areq, READ_LOCK);
! 	ObtainWriteLock(&afs_xcbhash, 469);
! 	avc->states |= CTruth;
! 	if (avc->callback /* check for race */ ) {
! 	    if (CallBack.ExpirationTime != 0) {
! 		avc->cbExpires = CallBack.ExpirationTime + start;
! 		avc->states |= CStatd;
! 		avc->states &= ~CBulkFetching;
! 		afs_QueueCallback(avc, CBHash(CallBack.ExpirationTime), volp);
! 	    } else if (avc->states & CRO) {	/* ordinary callback on a read-only volume -- AFS 3.2 style */
! 		avc->cbExpires = 3600 + start;
! 		avc->states |= CStatd;
! 		avc->states &= ~CBulkFetching;
! 		afs_QueueCallback(avc, CBHash(3600), volp);
! 	    } else {
! 		afs_DequeueCallback(avc);
! 		avc->callback = NULL;
! 		avc->states &= ~(CStatd | CUnique);
! 		if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
! 		    osi_dnlc_purgedp(avc);	/* if it (could be) a directory */
! 	    }
! 	} else {
! 	    afs_DequeueCallback(avc);
! 	    avc->callback = NULL;
! 	    avc->states &= ~(CStatd | CUnique);
! 	    if ((avc->states & CForeign) || (avc->fid.Fid.Vnode & 1))
! 		osi_dnlc_purgedp(avc);	/* if it (could be) a directory */
! 	}
! 	ReleaseWriteLock(&afs_xcbhash);
! 	if (volp)
! 	    afs_PutVolume(volp, READ_LOCK);
      } else {
  	/* used to undo the local callback, but that's too extreme.
  	 * There are plenty of good reasons that fetchstatus might return
--- 2589,2595 ----
  	      SHARED_LOCK, NULL));
  
      if (!code) {
! 	afs_UpdateStatus(avc, afid, areq, Outsp, &CallBack, start);
      } else {
  	/* used to undo the local callback, but that's too extreme.
  	 * There are plenty of good reasons that fetchstatus might return
Index: openafs/src/afs/discon.h
diff -c openafs/src/afs/discon.h:1.2.2.2 openafs/src/afs/discon.h:1.2.2.3
*** openafs/src/afs/discon.h:1.2.2.2	Fri May 23 10:25:16 2008
--- openafs/src/afs/discon.h	Mon Sep 22 15:29:54 2008
***************
*** 4,22 ****
--- 4,80 ----
  #ifndef AFS_DISCON_ENV
  #define AFS_IS_DISCONNECTED 0
  #define AFS_IS_LOGGING 0
+ #define AFS_IS_DISCON_RW 0
+ #define AFS_IN_SYNC 0
  #define AFS_DISCON_LOCK()
  #define AFS_DISCON_UNLOCK()
  
+ #define AFS_DISCON_ADD_DIRTY(avc)
+ 
  #else
  
  extern afs_int32    afs_is_disconnected;
  extern afs_int32    afs_is_logging;
+ extern afs_int32    afs_is_discon_rw;
+ extern afs_int32    afs_in_sync;
  extern afs_rwlock_t afs_discon_lock;
  
+ extern struct vcache *afs_DDirtyVCList;
+ extern struct vcache *afs_DDirtyVCListStart;
+ extern struct vcache *afs_DDirtyVCListPrev;
+ extern afs_rwlock_t afs_DDirtyVCListLock;
+ extern afs_int32 afs_ConflictPolicy;
+ 
+ extern void afs_RemoveAllConns();
+ extern afs_uint32 afs_DisconVnode; /* XXX: not protected. */
+ 
+ /* For afs_GenFakeFid. */
+ extern struct vcache *afs_FindVCache(struct VenusFid *afid,
+ 					afs_int32 *retry,
+ 					afs_int32 flag);
+ 
+ extern int afs_WriteVCacheDiscon(register struct vcache *avc,
+ 					register struct AFSStoreStatus *astatus,
+ 					struct vattr *attrs);
+ extern int afs_ResyncDisconFiles(struct vrequest *areq,
+ 					struct AFS_UCRED *acred);
+ extern void afs_RemoveAllConns();
+ extern void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype);
+ extern void afs_GenShadowFid(struct VenusFid *afid);
+ extern void afs_GenDisconStatus(struct vcache *adp,
+ 					struct vcache *avc,
+ 					struct VenusFid *afid,
+ 					struct vattr *attrs,
+ 					struct vrequest *areq,
+ 					int file_type);
+ extern int afs_HashOutDCache(struct dcache *adc, int zap);
+ extern int afs_MakeShadowDir(struct vcache *avc);
+ extern void afs_DeleteShadowDir(struct vcache *avc);
+ extern struct dcache *afs_FindDCacheByFid(register struct VenusFid *afid);
+ extern void afs_UpdateStatus(struct vcache *avc,
+ 					struct VenusFid *afid,
+ 					struct vrequest *areq,
+ 					struct AFSFetchStatus *Outsp,
+ 					struct AFSCallBack *acb,
+ 					afs_uint32 start);
+ extern void afs_RemoveAllConns();
+ 
  #define AFS_IS_DISCONNECTED (afs_is_disconnected)
  #define AFS_IS_LOGGING (afs_is_logging)
+ #define AFS_IS_DISCON_RW (afs_is_discon_rw)
+ #define AFS_IN_SYNC (afs_in_sync)
  #define AFS_DISCON_LOCK() ObtainReadLock(&afs_discon_lock)
  #define AFS_DISCON_UNLOCK() ReleaseReadLock(&afs_discon_lock)
  
+ #define AFS_DISCON_ADD_DIRTY(avc)				\
+ do {								\
+     if (!afs_DDirtyVCListStart) {				\
+     	afs_DDirtyVCListStart = afs_DDirtyVCList = avc;		\
+     } else {							\
+     	afs_DDirtyVCList->ddirty_next = avc;			\
+ 	afs_DDirtyVCList = avc;					\
+     }								\
+ } while(0);
+ 
  #endif /* AFS_DISCON_ENV */
  #endif /* _DISCON_H */
Index: openafs/src/afs/lock.h
diff -c openafs/src/afs/lock.h:1.17.4.6 openafs/src/afs/lock.h:1.17.4.7
*** openafs/src/afs/lock.h:1.17.4.6	Fri Nov  9 14:20:29 2007
--- openafs/src/afs/lock.h	Mon Sep 22 15:29:54 2008
***************
*** 31,37 ****
  /* This is the max lock number in use. Please update it if you add any new
   * lock numbers.
   */
! #define MAX_LOCK_NUMBER 700
  #endif
  
  struct afs_bozoLock {
--- 31,37 ----
  /* This is the max lock number in use. Please update it if you add any new
   * lock numbers.
   */
! #define MAX_LOCK_NUMBER 760
  #endif
  
  struct afs_bozoLock {
Index: openafs/src/afs/DARWIN/osi_vfsops.c
diff -c openafs/src/afs/DARWIN/osi_vfsops.c:1.17.4.1 openafs/src/afs/DARWIN/osi_vfsops.c:1.17.4.2
*** openafs/src/afs/DARWIN/osi_vfsops.c:1.17.4.1	Thu Jan  4 17:17:57 2007
--- openafs/src/afs/DARWIN/osi_vfsops.c	Fri Aug 22 15:26:48 2008
***************
*** 5,11 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/DARWIN/osi_vfsops.c,v 1.17.4.1 2007/01/04 22:17:57 shadow Exp $");
  
  #include <afs/sysincludes.h>	/* Standard vendor system headers */
  #include <afsincludes.h>	/* Afs-based standard headers */
--- 5,11 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/DARWIN/osi_vfsops.c,v 1.17.4.2 2008/08/22 19:26:48 shadow Exp $");
  
  #include <afs/sysincludes.h>	/* Standard vendor system headers */
  #include <afsincludes.h>	/* Afs-based standard headers */
***************
*** 383,389 ****
      abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
  	abp->f_ffree = 
  #ifdef AFS_DARWIN80_ENV
! 	2147483648
  #else
  	2000000
  #endif
--- 383,389 ----
      abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
  	abp->f_ffree = 
  #ifdef AFS_DARWIN80_ENV
!         0xffffffffffffffff
  #else
  	2000000
  #endif
Index: openafs/src/afs/FBSD/osi_file.c
diff -c openafs/src/afs/FBSD/osi_file.c:1.13.14.2 openafs/src/afs/FBSD/osi_file.c:1.13.14.3
*** openafs/src/afs/FBSD/osi_file.c:1.13.14.2	Thu Dec 13 14:18:32 2007
--- openafs/src/afs/FBSD/osi_file.c	Tue Aug 26 10:01:33 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_file.c,v 1.13.14.2 2007/12/13 19:18:32 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_file.c,v 1.13.14.3 2008/08/26 14:01:33 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 50,56 ****
  	osi_FreeSmallSpace(afile);
  	osi_Panic("UFSOpen: igetinode failed");
      }
! #if defined(AFS_FBSD50_ENV)
      VOP_UNLOCK(vp, 0, curthread);
  #else
      VOP_UNLOCK(vp, 0, curproc);
--- 50,58 ----
  	osi_FreeSmallSpace(afile);
  	osi_Panic("UFSOpen: igetinode failed");
      }
! #if defined(AFS_FBSD80_ENV)
!     VOP_UNLOCK(vp, 0);
! #elif defined(AFS_FBSD50_ENV)
      VOP_UNLOCK(vp, 0, curthread);
  #else
      VOP_UNLOCK(vp, 0, curproc);
***************
*** 71,77 ****
      AFS_STATCNT(osi_Stat);
      MObtainWriteLock(&afs_xosi, 320);
      AFS_GUNLOCK();
! #if defined(AFS_FBSD50_ENV)
      vn_lock(afile->vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
      code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
      VOP_UNLOCK(afile->vnode, LK_EXCLUSIVE, curthread);
--- 73,83 ----
      AFS_STATCNT(osi_Stat);
      MObtainWriteLock(&afs_xosi, 320);
      AFS_GUNLOCK();
! #if defined(AFS_FBSD80_ENV)
!     vn_lock(afile->vnode, LK_EXCLUSIVE | LK_RETRY);
!     code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
!     VOP_UNLOCK(afile->vnode, 0);
! #elif defined(AFS_FBSD50_ENV)
      vn_lock(afile->vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
      code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
      VOP_UNLOCK(afile->vnode, LK_EXCLUSIVE, curthread);
***************
*** 105,111 ****
  {
      struct vattr tvattr;
      struct vnode *vp;
!     register afs_int32 code;
      AFS_STATCNT(osi_Truncate);
  
      MObtainWriteLock(&afs_xosi, 321);
--- 111,117 ----
  {
      struct vattr tvattr;
      struct vnode *vp;
!     register afs_int32 code, glocked;
      AFS_STATCNT(osi_Truncate);
  
      MObtainWriteLock(&afs_xosi, 321);
***************
*** 115,122 ****
       * have very slow truncates, even when the file is already
       * small enough.  Check now and save some time.
       */
!     AFS_GUNLOCK();
! #if defined(AFS_FBSD50_ENV)
      vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
      code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
  #else
--- 121,133 ----
       * have very slow truncates, even when the file is already
       * small enough.  Check now and save some time.
       */
!     glocked = ISAFS_GLOCK();
!     if (glocked)
!       AFS_GUNLOCK();
! #if defined(AFS_FBSD80_ENV)
!     vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
!     code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
! #elif defined(AFS_FBSD50_ENV)
      vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
      code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
  #else
***************
*** 135,146 ****
  #endif
  
  out:
! #if defined(AFS_FBSD50_ENV)
      VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
  #else
      VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
  #endif
!     AFS_GLOCK();
      MReleaseWriteLock(&afs_xosi);
      return code;
  }
--- 146,160 ----
  #endif
  
  out:
! #if defined(AFS_FBSD80_ENV)
!     VOP_UNLOCK(vp, 0);
! #elif defined(AFS_FBSD50_ENV)
      VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
  #else
      VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
  #endif
!     if (glocked)
!       AFS_GLOCK();
      MReleaseWriteLock(&afs_xosi);
      return code;
  }
Index: openafs/src/afs/FBSD/osi_machdep.h
diff -c openafs/src/afs/FBSD/osi_machdep.h:1.13.4.2 openafs/src/afs/FBSD/osi_machdep.h:1.13.4.3
*** openafs/src/afs/FBSD/osi_machdep.h:1.13.4.2	Thu Nov  9 19:11:06 2006
--- openafs/src/afs/FBSD/osi_machdep.h	Tue Aug 26 10:01:33 2008
***************
*** 59,65 ****
  #undef afs_osi_Alloc_NoSleep
  #define afs_osi_Alloc_NoSleep(size) osi_fbsd_alloc((size), 0)
  
! #define VN_RELE(vp)		vrele(vp)
  #define VN_HOLD(vp)		VREF(vp)
  
  #ifdef AFS_FBSD60_ENV
--- 59,72 ----
  #undef afs_osi_Alloc_NoSleep
  #define afs_osi_Alloc_NoSleep(size) osi_fbsd_alloc((size), 0)
  
! #ifdef AFS_FBSD80_ENV
! #define VN_RELE(vp)				\
!   do {						\
!     vrele(vp);					\
!   } while(0);
! #else
! #define VN_RELE(vp)             vrele(vp)
! #endif
  #define VN_HOLD(vp)		VREF(vp)
  
  #ifdef AFS_FBSD60_ENV
***************
*** 84,93 ****
  #define AFS_GLOCK() mtx_lock(&afs_global_mtx)
  #define AFS_GUNLOCK() mtx_unlock(&afs_global_mtx)
  #define ISAFS_GLOCK() (mtx_owned(&afs_global_mtx))
- 
  #else /* FBSD50 */
  extern struct lock afs_global_lock;
- 
  #define osi_curcred()	(curproc->p_cred->pc_ucred)
  #define afs_suser(x)	(!suser(curproc))
  #define osi_getpid()	(curproc->p_pid)
--- 91,98 ----
Index: openafs/src/afs/FBSD/osi_misc.c
diff -c openafs/src/afs/FBSD/osi_misc.c:1.10 openafs/src/afs/FBSD/osi_misc.c:1.10.6.1
*** openafs/src/afs/FBSD/osi_misc.c:1.10	Tue Mar  8 16:57:53 2005
--- openafs/src/afs/FBSD/osi_misc.c	Tue Aug 26 10:01:33 2008
***************
*** 18,24 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_misc.c,v 1.10 2005/03/08 21:57:53 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 18,24 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_misc.c,v 1.10.6.1 2008/08/26 14:01:33 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 35,46 ****
  	       struct vnode **vpp)
  {
      struct nameidata n;
!     int flags, error, wasowned;
  
  #ifdef AFS_FBSD50_ENV
!     wasowned = mtx_owned(&afs_global_mtx);
!     if (wasowned)
! 	mtx_unlock(&afs_global_mtx);
  #endif
  
      flags = 0;
--- 35,46 ----
  	       struct vnode **vpp)
  {
      struct nameidata n;
!     int flags, error, glocked;
  
  #ifdef AFS_FBSD50_ENV
!     glocked = ISAFS_GLOCK();
!     if (glocked)
! 	AFS_GUNLOCK();
  #endif
  
      flags = 0;
***************
*** 49,69 ****
  	flags |= FOLLOW;
      else
  	flags |= NOFOLLOW;
      NDINIT(&n, LOOKUP, flags, seg, aname, curproc);
      if ((error = namei(&n)) != 0) {
  #ifdef AFS_FBSD50_ENV
! 	if (wasowned)
! 	    mtx_lock(&afs_global_mtx);
  #endif
  	return error;
      }
      *vpp = n.ni_vp;
!     /* should we do this? */
      VOP_UNLOCK(n.ni_vp, 0, curproc);
      NDFREE(&n, NDF_ONLY_PNBUF);
  #ifdef AFS_FBSD50_ENV
!     if (wasowned)
! 	mtx_lock(&afs_global_mtx);
  #endif
      return 0;
  }
--- 49,78 ----
  	flags |= FOLLOW;
      else
  	flags |= NOFOLLOW;
+ #ifdef AFS_FBSD80_ENV
+     flags |= MPSAFE; /* namei must take GIANT if needed */
+ #endif
      NDINIT(&n, LOOKUP, flags, seg, aname, curproc);
      if ((error = namei(&n)) != 0) {
  #ifdef AFS_FBSD50_ENV
! 	if (glocked)
! 	    AFS_GLOCK();
  #endif
  	return error;
      }
      *vpp = n.ni_vp;
!     /* XXX should we do this?  Usually NOT (matt) */
! #if defined(AFS_FBSD80_ENV)
!     /*VOP_UNLOCK(n.ni_vp, 0);*/
! #elif defined(AFS_FBSD50_ENV)
!     VOP_UNLOCK(n.ni_vp, 0, curthread);
! #else
      VOP_UNLOCK(n.ni_vp, 0, curproc);
+ #endif
      NDFREE(&n, NDF_ONLY_PNBUF);
  #ifdef AFS_FBSD50_ENV
!     if (glocked)
! 	AFS_GLOCK();
  #endif
      return 0;
  }
***************
*** 105,122 ****
  {
  	void *rv;
  #ifdef AFS_FBSD50_ENV
! 	int wasowned;
  
  	if (dropglobal) {
! 		wasowned = mtx_owned(&afs_global_mtx);
! 		if (wasowned)
! 			mtx_unlock(&afs_global_mtx);
! 		rv = malloc(size, M_AFS, M_WAITOK);
! 		if (wasowned)
! 			mtx_lock(&afs_global_mtx);
  	} else
  #endif
! 		rv = malloc(size, M_AFS, M_NOWAIT);
  
  	return (rv);
  }
--- 114,131 ----
  {
  	void *rv;
  #ifdef AFS_FBSD50_ENV
! 	int glocked;
  
  	if (dropglobal) {
! 	    glocked = ISAFS_GLOCK();
! 	    if (glocked)
! 		AFS_GUNLOCK();
! 	    rv = malloc(size, M_AFS, M_WAITOK);
! 	    if (glocked)
! 		AFS_GLOCK();
  	} else
  #endif
! 	    rv = malloc(size, M_AFS, M_NOWAIT);
  
  	return (rv);
  }
***************
*** 124,169 ****
  void
  osi_fbsd_free(void *p)
  {
! 
! 	free(p, M_AFS);
! }
! 
! void
! osi_AllocMoreSSpace(afs_int32 preallocs)
! {
! 	;
! }
! 
! void
! osi_FreeLargeSpace(void *p)
! {
! 	osi_fbsd_free(p);
! }
! 
! void
! osi_FreeSmallSpace(void *p)
! {
! 	osi_fbsd_free(p);
! }
! 
! void *
! osi_AllocLargeSpace(size_t size)
! {
! 	AFS_ASSERT_GLOCK();
! 	AFS_STATCNT(osi_AllocLargeSpace);
! 	return (osi_fbsd_alloc(size, 1));
! }
! 
! void *
! osi_AllocSmallSpace(size_t size)
! {
! 	AFS_ASSERT_GLOCK();
! 	AFS_STATCNT(osi_AllocSmallSpace);
! 	return (osi_fbsd_alloc(size, 1));
! }
! 
! void
! shutdown_osinet(void)
! {
! 	;
  }
--- 133,137 ----
  void
  osi_fbsd_free(void *p)
  {
!        free(p, M_AFS);
  }
Index: openafs/src/afs/FBSD/osi_vfsops.c
diff -c openafs/src/afs/FBSD/osi_vfsops.c:1.21 openafs/src/afs/FBSD/osi_vfsops.c:1.21.4.1
*** openafs/src/afs/FBSD/osi_vfsops.c:1.21	Fri Jul  8 12:53:43 2005
--- openafs/src/afs/FBSD/osi_vfsops.c	Tue Aug 26 10:01:33 2008
***************
*** 2,8 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_vfsops.c,v 1.21 2005/07/08 16:53:43 rees Exp $");
  
  #include <afs/sysincludes.h>	/* Standard vendor system headers */
  #include <afsincludes.h>	/* Afs-based standard headers */
--- 2,8 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_vfsops.c,v 1.21.4.1 2008/08/26 14:01:33 shadow Exp $");
  
  #include <afs/sysincludes.h>	/* Standard vendor system headers */
  #include <afsincludes.h>	/* Afs-based standard headers */
***************
*** 98,103 ****
--- 98,108 ----
      afs_globalVFS = mp;
      mp->vfs_bsize = 8192;
      vfs_getnewfsid(mp);
+ #ifdef AFS_FBSD70_ENV /* XXX 70? */
+     MNT_ILOCK(mp);
+     mp->mnt_flag &= ~MNT_LOCAL;
+     mp->mnt_kern_flag |= MNTK_MPSAFE; /* solid steel */
+ #endif
      mp->mnt_stat.f_iosize = 8192;
  
      if (path != NULL)
***************
*** 109,116 ****
--- 114,125 ----
      strcpy(mp->mnt_stat.f_mntfromname, "AFS");
      /* null terminated string "AFS" will fit, just leave it be. */
      strcpy(mp->mnt_stat.f_fstypename, "afs");
+ #ifdef AFS_FBSD70_ENV
+     MNT_IUNLOCK(mp);
+ #endif
      AFS_GUNLOCK();
      afs_statfs(mp, &mp->mnt_stat, p);
+ 
      return 0;
  }
  
***************
*** 140,146 ****
       * the root vnode (this is just a guess right now).
       * This has to be done outside the global lock.
       */
! #ifdef AFS_FBSD53_ENV
      vflush(mp, 1, (flags & MNT_FORCE) ? FORCECLOSE : 0, p);
  #else
      vflush(mp, 1, (flags & MNT_FORCE) ? FORCECLOSE : 0);
--- 149,157 ----
       * the root vnode (this is just a guess right now).
       * This has to be done outside the global lock.
       */
! #if defined(AFS_FBSD80_ENV)
!   /* do nothing */
! #elif defined(AFS_FBSD53_ENV)
      vflush(mp, 1, (flags & MNT_FORCE) ? FORCECLOSE : 0, p);
  #else
      vflush(mp, 1, (flags & MNT_FORCE) ? FORCECLOSE : 0);
***************
*** 184,195 ****
  	error = 0;
      } else {
  tryagain:
  	if (afs_globalVp) {
  	    afs_PutVCache(afs_globalVp);
  	    /* vrele() needed here or not? */
  	    afs_globalVp = NULL;
  	}
! 
  	if (!(error = afs_InitReq(&treq, cr)) && !(error = afs_CheckInit())) {
  	    tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
  	    /* we really want this to stay around */
--- 195,207 ----
  	error = 0;
      } else {
  tryagain:
+ #ifndef AFS_FBSD80_ENV
  	if (afs_globalVp) {
  	    afs_PutVCache(afs_globalVp);
  	    /* vrele() needed here or not? */
  	    afs_globalVp = NULL;
  	}
! #endif
  	if (!(error = afs_InitReq(&treq, cr)) && !(error = afs_CheckInit())) {
  	    tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
  	    /* we really want this to stay around */
Index: openafs/src/afs/FBSD/osi_vm.c
diff -c openafs/src/afs/FBSD/osi_vm.c:1.15 openafs/src/afs/FBSD/osi_vm.c:1.15.4.1
*** openafs/src/afs/FBSD/osi_vm.c:1.15	Mon May 23 17:04:08 2005
--- openafs/src/afs/FBSD/osi_vm.c	Tue Aug 26 10:01:33 2008
***************
*** 20,28 ****
  
  #include <afsconfig.h>
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_vm.c,v 1.15 2005/05/23 21:04:08 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 20,34 ----
  
  #include <afsconfig.h>
  #include "afs/param.h"
+ #ifdef AFS_FBSD70_ENV
+ #include <sys/param.h>
+ #include <sys/vnode.h>
+      void
+      vgonel(struct vnode *vp, struct thread *td);
+ #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_vm.c,v 1.15.4.1 2008/08/26 14:01:33 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 52,58 ****
  #define VOP_GETVOBJECT(vp, objp) (*(objp) = (vp)->v_object)
  #endif
  
! #ifdef AFS_FBSD50_ENV
  #define	lock_vnode(v)	vn_lock((v), LK_EXCLUSIVE | LK_RETRY, curthread)
  #define unlock_vnode(v)	VOP_UNLOCK((v), 0, curthread)
  #else
--- 58,67 ----
  #define VOP_GETVOBJECT(vp, objp) (*(objp) = (vp)->v_object)
  #endif
  
! #if defined(AFS_FBSD80_ENV)
! #define	lock_vnode(v)	vn_lock((v), LK_EXCLUSIVE | LK_RETRY)
! #define unlock_vnode(v)	VOP_UNLOCK((v), 0)
! #elif defined(AFS_FBSD50_ENV)
  #define	lock_vnode(v)	vn_lock((v), LK_EXCLUSIVE | LK_RETRY, curthread)
  #define unlock_vnode(v)	VOP_UNLOCK((v), 0, curthread)
  #else
***************
*** 96,118 ****
      if (CheckLock(&avc->lock))
  	return EBUSY;
  
      AFS_GUNLOCK();
      vp = AFSTOV(avc);
      lock_vnode(vp);
      if (VOP_GETVOBJECT(vp, &obj) == 0) {
  	VM_OBJECT_LOCK(obj);
  	vm_object_page_remove(obj, 0, 0, FALSE);
! #if 0
  	if (obj->ref_count == 0) {
- 	    vgonel(vp, curproc);
  	    simple_lock(&vp->v_interlock);
  	    vp->v_tag = VT_AFS;
  	    SetAfsVnode(vp);
  	}
  #endif
  	VM_OBJECT_UNLOCK(obj);
      }
      unlock_vnode(vp);
      AFS_GLOCK();
  
      return 0;
--- 105,133 ----
      if (CheckLock(&avc->lock))
  	return EBUSY;
  
+     return(0);
+ 
      AFS_GUNLOCK();
      vp = AFSTOV(avc);
+ #ifndef AFS_FBSD70_ENV
      lock_vnode(vp);
+ #endif
      if (VOP_GETVOBJECT(vp, &obj) == 0) {
  	VM_OBJECT_LOCK(obj);
  	vm_object_page_remove(obj, 0, 0, FALSE);
! #if 1
  	if (obj->ref_count == 0) {
  	    simple_lock(&vp->v_interlock);
+ 	    vgonel(vp, curthread);
  	    vp->v_tag = VT_AFS;
  	    SetAfsVnode(vp);
  	}
  #endif
  	VM_OBJECT_UNLOCK(obj);
      }
+ #ifndef AFS_FBSD70_ENV
      unlock_vnode(vp);
+ #endif
      AFS_GLOCK();
  
      return 0;
***************
*** 146,170 ****
       */
      do {
  	anyio = 0;
  	lock_vnode(vp);
  	if (VOP_GETVOBJECT(vp, &obj) == 0 && (obj->flags & OBJ_MIGHTBEDIRTY)) {
! 	    /* XXX - obj locking? */
  	    unlock_vnode(vp);
  #ifdef AFS_FBSD50_ENV
  	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY, curthread)) {
  #else
! 	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ, curproc)) {
  #endif
! 		if (VOP_GETVOBJECT(vp, &obj) == 0) {
! 		    VM_OBJECT_LOCK(obj);
! 		    vm_object_page_clean(obj, 0, 0, OBJPC_SYNC);
! 		    VM_OBJECT_UNLOCK(obj);
! 		    anyio = 1;
  		}
- 		vput(vp);
  	    }
! 	} else
! 	    unlock_vnode(vp);
      } while (anyio && (--tries > 0));
      AFS_GLOCK();
      ObtainWriteLock(&avc->lock, 94);
--- 161,191 ----
       */
      do {
  	anyio = 0;
+ #ifdef AFS_FBSD80_ENV
  	lock_vnode(vp);
+ #endif
  	if (VOP_GETVOBJECT(vp, &obj) == 0 && (obj->flags & OBJ_MIGHTBEDIRTY)) {
! #ifdef AFS_FBSD80_ENV
  	    unlock_vnode(vp);
+ #endif
  #ifdef AFS_FBSD50_ENV
  	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY, curthread)) {
  #else
! 		if (!vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ, curproc)) {
  #endif
! 		    if (VOP_GETVOBJECT(vp, &obj) == 0) {
! 			VM_OBJECT_LOCK(obj);
! 			vm_object_page_clean(obj, 0, 0, OBJPC_SYNC);
! 			VM_OBJECT_UNLOCK(obj);
! 			anyio = 1;
! 		    }
! 		    vput(vp);
  		}
  	    }
! #ifdef AFS_FBSD80_ENV
! 	    else
! 		unlock_vnode(vp);
! #endif
      } while (anyio && (--tries > 0));
      AFS_GLOCK();
      ObtainWriteLock(&avc->lock, 94);
***************
*** 184,235 ****
  {
      struct vnode *vp;
      struct vm_object *obj;
!     int anyio, tries;
  
-     ReleaseWriteLock(&avc->lock);
-     AFS_GUNLOCK();
-     tries = 5;
      vp = AFSTOV(avc);
!     do {
! 	anyio = 0;
! 	lock_vnode(vp);
! 	/* See the comments above. */
! 	if (VOP_GETVOBJECT(vp, &obj) == 0 && (obj->flags & OBJ_MIGHTBEDIRTY)) {
! 	    /* XXX - obj locking */
! 	    unlock_vnode(vp);
! #ifdef AFS_FBSD50_ENV
! 	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY, curthread)) {
! #else
! 	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ, curproc)) {
! #endif
! 		if (VOP_GETVOBJECT(vp, &obj) == 0) {
! 		    VM_OBJECT_LOCK(obj);
! 		    /*
! 		     * Do we really want OBJPC_SYNC?  OBJPC_INVAL would be
! 		     * faster, if invalidation is really what we are being
! 		     * asked to do.  (It would make more sense, too, since
! 		     * otherwise this function is practically identical to
! 		     * osi_VM_StoreAllSegments().)  -GAW
! 		     */
! 		    vm_object_page_clean(obj, 0, 0, OBJPC_SYNC);
! 		    VM_OBJECT_UNLOCK(obj);
! 		    anyio = 1;
! 		}
! 		vput(vp);
! 	    }
! 	} else
! 	    unlock_vnode(vp);
!     } while (anyio && (--tries > 0));
!     lock_vnode(vp);
!     if (VOP_GETVOBJECT(vp, &obj) == 0) {
! 	VM_OBJECT_LOCK(obj);
! 	vm_object_page_remove(obj, 0, 0, FALSE);
! 	VM_OBJECT_UNLOCK(obj);
      }
!     unlock_vnode(vp);
!     /*vinvalbuf(AFSTOV(avc),0, NOCRED, curproc, 0,0); */
!     AFS_GLOCK();
!     ObtainWriteLock(&avc->lock, 59);
  }
  
  /* Purge VM for a file when its callback is revoked.
--- 205,248 ----
  {
      struct vnode *vp;
      struct vm_object *obj;
!     int anyio, tries, code;
! 
!     SPLVAR;
  
      vp = AFSTOV(avc);
! 
!     if (vp->v_iflag & VI_DOOMED) {
!       USERPRI;
!       return 0;
      }
! 
!     if (vp->v_bufobj.bo_object != NULL) {
!       VM_OBJECT_LOCK(vp->v_bufobj.bo_object);
!       /*
!        * Do we really want OBJPC_SYNC?  OBJPC_INVAL would be
!        * faster, if invalidation is really what we are being
!        * asked to do.  (It would make more sense, too, since
!        * otherwise this function is practically identical to
!        * osi_VM_StoreAllSegments().)  -GAW
!        */
! 
!       /*
!        * Dunno.  We no longer resemble osi_VM_StoreAllSegments,
!        * though maybe that's wrong, now.  And OBJPC_SYNC is the
!        * common thing in 70 file systems, it seems.  Matt.
!        */
! 
!       vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC);
!       VM_OBJECT_UNLOCK(vp->v_bufobj.bo_object);
!     }
! 
!     tries = 5;
!     code = vinvalbuf(vp, V_SAVE, curthread, PCATCH, 0);
!     while (code && (tries > 0)) {
!       code = vinvalbuf(vp, V_SAVE, curthread, PCATCH, 0);
!       --tries;
!     }
!     USERPRI;
  }
  
  /* Purge VM for a file when its callback is revoked.
Index: openafs/src/afs/FBSD/osi_vnodeops.c
diff -c openafs/src/afs/FBSD/osi_vnodeops.c:1.22.6.1 openafs/src/afs/FBSD/osi_vnodeops.c:1.22.6.2
*** openafs/src/afs/FBSD/osi_vnodeops.c:1.22.6.1	Tue Jan 15 01:09:11 2008
--- openafs/src/afs/FBSD/osi_vnodeops.c	Tue Aug 26 10:01:33 2008
***************
*** 48,54 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_vnodeops.c,v 1.22.6.1 2008/01/15 06:09:11 shadow Exp $");
  
  #include <afs/sysincludes.h>	/* Standard vendor system headers */
  #include <afsincludes.h>	/* Afs-based standard headers */
--- 48,54 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/FBSD/osi_vnodeops.c,v 1.22.6.2 2008/08/26 14:01:33 shadow Exp $");
  
  #include <afs/sysincludes.h>	/* Standard vendor system headers */
  #include <afsincludes.h>	/* Afs-based standard headers */
***************
*** 95,100 ****
--- 95,105 ----
  static vop_strategy_t	afs_vop_strategy;
  static vop_symlink_t	afs_vop_symlink;
  static vop_write_t	afs_vop_write;
+ #if defined(AFS_FBSD70_ENV) && !defined(AFS_FBSD90_ENV)
+ static vop_lock1_t      afs_vop_lock;
+ static vop_unlock_t     afs_vop_unlock;
+ static vop_islocked_t   afs_vop_islocked;
+ #endif
  
  struct vop_vector afs_vnodeops = {
  	.vop_default =		&default_vnodeops,
***************
*** 128,133 ****
--- 133,143 ----
  	.vop_strategy =		afs_vop_strategy,
  	.vop_symlink =		afs_vop_symlink,
  	.vop_write =		afs_vop_write,
+ #if defined(AFS_FBSD70_ENV) && !defined(AFS_FBSD90_ENV)
+ 	.vop_lock1 =            afs_vop_lock,
+ 	.vop_unlock =           afs_vop_unlock,
+ 	.vop_islocked =         afs_vop_islocked,
+ #endif
  };
  
  #else /* AFS_FBSD60_ENV */
***************
*** 213,218 ****
--- 223,233 ----
      {&vop_write_desc, (vop_t *) afs_vop_write},	/* write */
      {&vop_ioctl_desc, (vop_t *) afs_vop_ioctl},	/* XXX ioctl */
      /*{ &vop_seek_desc, afs_vop_seek }, *//* seek */
+ #if defined(AFS_FBSD70_ENV) && !defined(AFS_FBSD90_ENV)
+     {&vop_lock1_desc, (vop_t *) afs_vop_lock}, /* lock */
+     {&vop_unlock_desc, (vop_t *) afs_vop_unlock}, /* unlock */
+     {&vop_islocked_desc, (vop_t *) afs_vop_islocked}, /* islocked */
+ #endif
      {NULL, NULL}
  };
  struct vnodeopv_desc afs_vnodeop_opv_desc =
***************
*** 233,238 ****
--- 248,370 ----
  #define a_p a_td
  #endif
  
+ #if defined(AFS_FBSD80_ENV)
+ #define ma_vn_lock(vp, flags, p) (vn_lock(vp, flags))
+ #define MA_VOP_LOCK(vp, flags, p) (VOP_LOCK(vp, flags))
+ #define MA_VOP_UNLOCK(vp, flags, p) (VOP_UNLOCK(vp, flags))
+ #else
+ #define ma_vn_lock(vp, flags, p) (vn_lock(vp, flags, p))
+ #define MA_VOP_LOCK(vp, flags, p) (VOP_LOCK(vp, flags, p))
+ #define MA_VOP_UNLOCK(vp, flags, p) (VOP_UNLOCK(vp, flags, p))
+ #endif
+ 
+ #ifdef AFS_FBSD70_ENV
+ #ifndef AFS_FBSD80_ENV
+ /* From kern_lock.c */
+ #define	COUNT(td, x)	if ((td)) (td)->td_locks += (x)
+ #define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \
+ 	LK_SHARE_NONZERO | LK_WAIT_NONZERO)
+ 
+ static __inline void
+ sharelock(struct thread *td, struct lock *lkp, int incr) {
+ 	lkp->lk_flags |= LK_SHARE_NONZERO;
+ 	lkp->lk_sharecount += incr;
+ 	COUNT(td, incr);
+ }
+ #endif
+ 
+ /*
+  * Standard lock, unlock and islocked functions.
+  */
+ int
+ afs_vop_lock(ap)
+     struct vop_lock1_args /* {
+ 			     struct vnode *a_vp;
+ 			     int a_flags;
+ 			     struct thread *a_td;
+ 			     char *file;
+ 			     int line;
+ 			     } */ *ap;
+ {
+     struct vnode *vp = ap->a_vp;
+     struct lock *lkp = vp->v_vnlock;
+ 
+ #if 0 && defined(AFS_FBSD80_ENV) && !defined(UKERNEL)
+     afs_warn("afs_vop_lock: tid %d pid %d \"%s\"\n", curthread->td_tid,
+ 	     curthread->td_proc->p_pid, curthread->td_name);
+     kdb_backtrace();
+ #endif
+ 
+ #ifdef AFS_FBSD80_ENV
+     return (_lockmgr_args(lkp, ap->a_flags, VI_MTX(vp),
+ 			  LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT,
+ 			  ap->a_file, ap->a_line));
+ #else
+     return (_lockmgr(lkp, ap->a_flags, VI_MTX(vp), ap->a_td, ap->a_file, ap->a_line));
+ #endif
+ }
+ 
+ /* See above. */
+ int
+ afs_vop_unlock(ap)
+     struct vop_unlock_args /* {
+ 			      struct vnode *a_vp;
+ 			      int a_flags;
+ 			      struct thread *a_td;
+ 			      } */ *ap;
+ {
+     struct vnode *vp = ap->a_vp;
+     struct lock *lkp = vp->v_vnlock;
+ 
+ #ifdef AFS_FBSD80_ENV
+     int code;
+     u_int op;
+     op = ((ap->a_flags) | LK_RELEASE) & LK_TYPE_MASK;
+     int glocked = ISAFS_GLOCK();
+     if (glocked)
+ 	AFS_GUNLOCK();
+     if ((op & (op - 1)) != 0) {
+       afs_warn("afs_vop_unlock: Shit.\n");
+       goto done;
+     }
+     code = lockmgr(lkp, ap->a_flags | LK_RELEASE, VI_MTX(vp));
+  done:
+     if (glocked)
+ 	AFS_GLOCK();
+     return(code);
+ #else
+     /* possibly in current code path where this
+      * forces trace, we should have had a (shared? not
+      * necessarily, see _lockmgr in kern_lock.c) lock
+      * and that's the real bug.  but. 
+      */
+     critical_enter();
+     if ((lkp->lk_exclusivecount == 0) &&
+ 	(!(lkp->lk_flags & LK_SHARE_NONZERO))) {
+ 	sharelock(ap->a_td, lkp, 1);
+     }
+     critical_exit();
+     return (lockmgr(lkp, ap->a_flags | LK_RELEASE, VI_MTX(vp),
+ 		    ap->a_td));
+ #endif
+ }
+ 
+ /* See above. */
+ int
+ afs_vop_islocked(ap)
+     struct vop_islocked_args /* {
+ 				struct vnode *a_vp;
+ 				struct thread *a_td; (not in 80)
+ 				} */ *ap;
+ {
+ #ifdef AFS_FBSD80_ENV
+     return (lockstatus(ap->a_vp->v_vnlock));
+ #else
+     return (lockstatus(ap->a_vp->v_vnlock, ap->a_td));
+ #endif
+ }
+ #endif /* 70 */
+ 
  /*
   * Mosty copied from sys/ufs/ufs/ufs_vnops.c:ufs_pathconf().
   * We should know the correct answers to these questions with
***************
*** 346,370 ****
  #else
      struct proc *p = ap->a_cnp->cn_proc;
  #endif
      GETNAME();
  
      lockparent = flags & LOCKPARENT;
      wantparent = flags & (LOCKPARENT | WANTPARENT);
  
!     if (ap->a_dvp->v_type != VDIR) {
! 	*ap->a_vpp = 0;
! 	DROPNAME();
! 	return ENOTDIR;
!     }
!     dvp = ap->a_dvp;
      if (flags & ISDOTDOT)
  	VOP_UNLOCK(dvp, 0, p);
      AFS_GLOCK();
      error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
      AFS_GUNLOCK();
      if (error) {
  	if (flags & ISDOTDOT)
! 	    VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  	if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
  	    && (flags & ISLASTCN) && error == ENOENT)
  	    error = EJUSTRETURN;
--- 478,516 ----
  #else
      struct proc *p = ap->a_cnp->cn_proc;
  #endif
+ 
+     dvp = ap->a_dvp;
+     if (dvp->v_type != VDIR) {
+ #ifndef AFS_FBSD70_ENV
+ 	*ap->a_vpp = 0;
+ #endif
+ 	return ENOTDIR;
+     }
+ 
+     if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
+ 	return EIO;
+ 
      GETNAME();
  
      lockparent = flags & LOCKPARENT;
      wantparent = flags & (LOCKPARENT | WANTPARENT);
  
! #ifdef AFS_FBSD80_ENV
!     cnp->cn_flags |= MPSAFE; /* steel */
! #endif
! 
! #ifndef AFS_FBSD70_ENV
      if (flags & ISDOTDOT)
  	VOP_UNLOCK(dvp, 0, p);
+ #endif
+ 
      AFS_GLOCK();
      error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
      AFS_GUNLOCK();
+ 
      if (error) {
  	if (flags & ISDOTDOT)
! 	    MA_VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  	if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
  	    && (flags & ISLASTCN) && error == ENOENT)
  	    error = EJUSTRETURN;
***************
*** 381,390 ****
       * we also always return the vnode locked. */
  
      if (flags & ISDOTDOT) {
! 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  	/* always return the child locked */
  	if (lockparent && (flags & ISLASTCN)
! 	    && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
  	    vput(vp);
  	    DROPNAME();
  	    return (error);
--- 527,536 ----
       * we also always return the vnode locked. */
  
      if (flags & ISDOTDOT) {
! 	ma_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  	/* always return the child locked */
  	if (lockparent && (flags & ISLASTCN)
! 	    && (error = ma_vn_lock(dvp, LK_EXCLUSIVE, p))) {
  	    vput(vp);
  	    DROPNAME();
  	    return (error);
***************
*** 393,401 ****
  	/* they're the same; afs_lookup() already ref'ed the leaf.
  	 * It came in locked, so we don't need to ref OR lock it */
      } else {
! 	if (!lockparent || !(flags & ISLASTCN))
! 	    VOP_UNLOCK(dvp, 0, p);	/* done with parent. */
! 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  	/* always return the child locked */
      }
      *ap->a_vpp = vp;
--- 539,550 ----
  	/* they're the same; afs_lookup() already ref'ed the leaf.
  	 * It came in locked, so we don't need to ref OR lock it */
      } else {
! 	if (!lockparent || !(flags & ISLASTCN)) {
! #ifndef AFS_FBSD70_ENV /* 6 too? */
! 	    MA_VOP_UNLOCK(dvp, 0, p);	/* done with parent. */
! #endif
! 	}
! 	ma_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  	/* always return the child locked */
      }
      *ap->a_vpp = vp;
***************
*** 440,446 ****
  
      if (vcp) {
  	*ap->a_vpp = AFSTOV(vcp);
! 	vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
      } else
  	*ap->a_vpp = 0;
  
--- 589,595 ----
  
      if (vcp) {
  	*ap->a_vpp = AFSTOV(vcp);
! 	ma_vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
      } else
  	*ap->a_vpp = 0;
  
***************
*** 747,753 ****
  	     */
  	    if (!code) {
  #if defined(AFS_FBSD70_ENV)
! 		if(0) /* XXXX fixme for 7.0 */
  #else
  		if (m->flags & PG_WANTED)
  #endif
--- 896,902 ----
  	     */
  	    if (!code) {
  #if defined(AFS_FBSD70_ENV)
! 		if (m->oflags & VPO_WANTED)
  #else
  		if (m->flags & PG_WANTED)
  #endif
***************
*** 1012,1025 ****
  	error = EISDIR;
  	goto out;
      }
!     if ((error = vn_lock(vp, LK_EXCLUSIVE, p)) != 0) {
  	goto out;
      }
      AFS_GLOCK();
      error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
      AFS_GUNLOCK();
      if (dvp != vp)
! 	VOP_UNLOCK(vp, 0, p);
    out:
      DROPNAME();
      return error;
--- 1161,1174 ----
  	error = EISDIR;
  	goto out;
      }
!     if ((error = ma_vn_lock(vp, LK_EXCLUSIVE, p)) != 0) {
  	goto out;
      }
      AFS_GLOCK();
      error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
      AFS_GUNLOCK();
      if (dvp != vp)
! 	MA_VOP_UNLOCK(vp, 0, p);
    out:
      DROPNAME();
      return error;
***************
*** 1108,1114 ****
  	vput(fvp);
  	return (error);
      }
!     if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
  	goto abortit;
  
      MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
--- 1257,1263 ----
  	vput(fvp);
  	return (error);
      }
!     if ((error = ma_vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
  	goto abortit;
  
      MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
***************
*** 1171,1177 ****
      }
      if (vcp) {
  	*ap->a_vpp = AFSTOV(vcp);
! 	vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
      } else
  	*ap->a_vpp = 0;
      DROPNAME();
--- 1320,1326 ----
      }
      if (vcp) {
  	*ap->a_vpp = AFSTOV(vcp);
! 	ma_vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p);
      } else
  	*ap->a_vpp = 0;
      DROPNAME();
***************
*** 1226,1234 ****
  	if (error == 0) {
  	    newvp = AFSTOV(vcp);
  #ifdef AFS_FBSD50_ENV
! 	    vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_thread);
  #else
! 	    vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
  #endif
  	}
      }
--- 1375,1383 ----
  	if (error == 0) {
  	    newvp = AFSTOV(vcp);
  #ifdef AFS_FBSD50_ENV
! 	    ma_vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_thread);
  #else
! 	    ma_vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
  #endif
  	}
      }
***************
*** 1321,1327 ****
      AFS_GLOCK();
      afs_InactiveVCache(VTOAFS(vp), 0);	/* decrs ref counts */
      AFS_GUNLOCK();
!     VOP_UNLOCK(vp, 0, ap->a_p);
      return 0;
  }
  
--- 1470,1478 ----
      AFS_GLOCK();
      afs_InactiveVCache(VTOAFS(vp), 0);	/* decrs ref counts */
      AFS_GUNLOCK();
! #ifndef AFS_FBSD80_ENV
!     MA_VOP_UNLOCK(vp, 0, ap->a_p);
! #endif
      return 0;
  }
  
***************
*** 1362,1369 ****
      if (code)
  	printf("afs_vop_reclaim: afs_FlushVCache failed code %d\n", code);
  #ifdef AFS_FBSD60_ENV
!     else
  	vnode_destroy_vobject(vp);
  #endif
      return 0;
  }
--- 1513,1525 ----
      if (code)
  	printf("afs_vop_reclaim: afs_FlushVCache failed code %d\n", code);
  #ifdef AFS_FBSD60_ENV
!     else {
  	vnode_destroy_vobject(vp);
+ #ifndef AFS_FBSD70_ENV
+ 	vfs_hash_remove(vp);
+ #endif
+ 	vp->v_data = 0;
+     }
  #endif
      return 0;
  }
Index: openafs/src/afs/LINUX/osi_alloc.c
diff -c openafs/src/afs/LINUX/osi_alloc.c:1.23.8.1 openafs/src/afs/LINUX/osi_alloc.c:1.23.8.2
*** openafs/src/afs/LINUX/osi_alloc.c:1.23.8.1	Wed Apr 18 14:02:47 2007
--- openafs/src/afs/LINUX/osi_alloc.c	Mon Sep 22 15:35:26 2008
***************
*** 15,21 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_alloc.c,v 1.23.8.1 2007/04/18 18:02:47 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 15,21 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_alloc.c,v 1.23.8.2 2008/09/22 19:35:26 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 366,371 ****
--- 366,372 ----
  	afs_atomlist_put(al_mem_pool, lmp);	/* return osi_linux_mem struct to pool */
  	afs_linux_cur_allocs--;
      } else {
+ 	BUG();
  	printf("osi_linux_free: failed to remove chunk from hashtable\n");
      }
  
Index: openafs/src/afs/LINUX/osi_module.c
diff -c openafs/src/afs/LINUX/osi_module.c:1.74.2.9 openafs/src/afs/LINUX/osi_module.c:1.74.2.10
*** openafs/src/afs/LINUX/osi_module.c:1.74.2.9	Wed Oct 24 14:22:21 2007
--- openafs/src/afs/LINUX/osi_module.c	Mon Sep 22 15:35:26 2008
***************
*** 15,21 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_module.c,v 1.74.2.9 2007/10/24 18:22:21 shadow Exp $");
  
  #include <linux/module.h> /* early to avoid printf->printk mapping */
  #include "afs/sysincludes.h"
--- 15,21 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_module.c,v 1.74.2.10 2008/09/22 19:35:26 shadow Exp $");
  
  #include <linux/module.h> /* early to avoid printf->printk mapping */
  #include "afs/sysincludes.h"
***************
*** 111,117 ****
      osi_proc_init();
      osi_ioctl_init();
  #endif
! 
      return 0;
  }
  
--- 111,119 ----
      osi_proc_init();
      osi_ioctl_init();
  #endif
! #if defined(AFS_CACHE_BYPASS)
!     afs_warn("Cache bypass patched libafs module init.\n");
! #endif
      return 0;
  }
  
***************
*** 123,128 ****
--- 125,133 ----
  cleanup_module(void)
  #endif
  {
+ #if defined(AFS_CACHE_BYPASS)
+     afs_warn("Cache bypass patched libafs module cleaning up.\n");
+ #endif
  #ifdef LINUX_KEYRING_SUPPORT
      osi_keyring_shutdown();
  #endif
Index: openafs/src/afs/LINUX/osi_vnodeops.c
diff -c openafs/src/afs/LINUX/osi_vnodeops.c:1.126.2.28 openafs/src/afs/LINUX/osi_vnodeops.c:1.126.2.31
*** openafs/src/afs/LINUX/osi_vnodeops.c:1.126.2.28	Mon Jul  7 12:53:59 2008
--- openafs/src/afs/LINUX/osi_vnodeops.c	Thu Sep 25 07:42:43 2008
***************
*** 22,28 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v 1.126.2.28 2008/07/07 16:53:59 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 22,28 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v 1.126.2.31 2008/09/25 11:42:43 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 37,42 ****
--- 37,47 ----
  #endif
  #if defined(AFS_LINUX26_ENV)
  #include "h/writeback.h"
+ #include "h/pagevec.h"
+ #endif
+ #if defined(AFS_CACHE_BYPASS)
+ #include "afs/lock.h"
+ #include "afs/afs_bypasscache.h"
  #endif
  
  #ifdef pgoff2loff
***************
*** 46,55 ****
--- 51,79 ----
  #endif
  
  #if defined(AFS_LINUX26_ENV)
+ #define LockPage(pp) lock_page(pp)
  #define UnlockPage(pp) unlock_page(pp)
  #endif
  
  extern struct vcache *afs_globalVp;
+ #if defined(AFS_LINUX26_ENV)
+ /* Some uses of BKL are perhaps not needed for bypass or memcache--
+  * why don't we try it out? */
+ extern struct afs_cacheOps afs_UfsCacheOps;
+ #define maybe_lock_kernel()			\
+     do {					       \
+ 	if(afs_cacheType == &afs_UfsCacheOps)	       \
+ 	    lock_kernel();			       \
+     } while(0);
+ 
+ 
+ #define maybe_unlock_kernel()			\
+     do {					       \
+ 	if(afs_cacheType == &afs_UfsCacheOps)	       \
+ 	    unlock_kernel();			       \
+     } while(0);
+ #endif /* AFS_CACHE_BYPASS */
+ 
  static ssize_t
  afs_linux_read(struct file *fp, char *buf, size_t count, loff_t * offp)
  {
***************
*** 57,68 ****
      struct vcache *vcp = VTOAFS(fp->f_dentry->d_inode);
      cred_t *credp = crref();
      struct vrequest treq;
! 
      AFS_GLOCK();
      afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
  	       ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
  	       99999);
- 
      /* get a validated vcache entry */
      code = afs_InitReq(&treq, credp);
      if (!code)
--- 81,91 ----
      struct vcache *vcp = VTOAFS(fp->f_dentry->d_inode);
      cred_t *credp = crref();
      struct vrequest treq;
!     afs_size_t isize, offindex;
      AFS_GLOCK();
      afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
  	       ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
  	       99999);
      /* get a validated vcache entry */
      code = afs_InitReq(&treq, credp);
      if (!code)
***************
*** 71,76 ****
--- 94,106 ----
      if (code)
  	code = -code;
      else {
+         isize = (i_size_read(fp->f_mapping->host) - 1) >> PAGE_CACHE_SHIFT;
+         offindex = *offp >> PAGE_CACHE_SHIFT;
+         if(offindex > isize) {
+             code=0;
+             goto done;
+         }
+ 
  	    osi_FlushPages(vcp, credp);	/* ensure stale pages are gone */
  	    AFS_GUNLOCK();
  #ifdef DO_SYNC_READ
***************
*** 84,90 ****
      afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
  	       ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
  	       code);
! 
      AFS_GUNLOCK();
      crfree(credp);
      return code;
--- 114,120 ----
      afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
  	       ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
  	       code);
! done:
      AFS_GUNLOCK();
      crfree(credp);
      return code;
***************
*** 167,173 ****
      struct afs_fakestat_state fakestat;
  
  #if defined(AFS_LINUX26_ENV)
!     lock_kernel();
  #endif
      AFS_GLOCK();
      AFS_STATCNT(afs_readdir);
--- 197,203 ----
      struct afs_fakestat_state fakestat;
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
      AFS_STATCNT(afs_readdir);
***************
*** 325,331 ****
  out1:
      AFS_GUNLOCK();
  #if defined(AFS_LINUX26_ENV)
!     unlock_kernel();
  #endif
      return code;
  }
--- 355,361 ----
  out1:
      AFS_GUNLOCK();
  #if defined(AFS_LINUX26_ENV)
!     maybe_unlock_kernel();
  #endif
      return code;
  }
***************
*** 399,411 ****
      int code;
  
  #ifdef AFS_LINUX24_ENV
!     lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_open(&vcp, fp->f_flags, credp);
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     unlock_kernel();
  #endif
  
      crfree(credp);
--- 429,441 ----
      int code;
  
  #ifdef AFS_LINUX24_ENV
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_open(&vcp, fp->f_flags, credp);
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     maybe_unlock_kernel();
  #endif
  
      crfree(credp);
***************
*** 420,432 ****
      int code = 0;
  
  #ifdef AFS_LINUX24_ENV
!     lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_close(vcp, fp->f_flags, credp);
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     unlock_kernel();
  #endif
  
      crfree(credp);
--- 450,462 ----
      int code = 0;
  
  #ifdef AFS_LINUX24_ENV
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_close(vcp, fp->f_flags, credp);
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     maybe_unlock_kernel();
  #endif
  
      crfree(credp);
***************
*** 445,457 ****
      cred_t *credp = crref();
  
  #ifdef AFS_LINUX24_ENV
!     lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_fsync(VTOAFS(ip), credp);
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     unlock_kernel();
  #endif
      crfree(credp);
      return -code;
--- 475,487 ----
      cred_t *credp = crref();
  
  #ifdef AFS_LINUX24_ENV
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_fsync(VTOAFS(ip), credp);
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     maybe_unlock_kernel();
  #endif
      crfree(credp);
      return -code;
***************
*** 585,590 ****
--- 615,623 ----
      struct vcache *vcp;
      cred_t *credp;
      int code;
+ #if defined(AFS_CACHE_BYPASS)
+     int bypasscache;
+ #endif
  
      AFS_GLOCK();
  
***************
*** 593,615 ****
  	return 0;
      }
  
      credp = crref();
      vcp = VTOAFS(FILE_INODE(fp));
  
      code = afs_InitReq(&treq, credp);
      if (code)
  	goto out;
  
      ObtainSharedLock(&vcp->lock, 535);
      if ((vcp->execsOrWriters > 0) && (file_count(fp) == 1)) {
  	UpgradeSToWLock(&vcp->lock, 536);
! 	code = afs_StoreAllSegments(vcp, &treq, AFS_SYNC | AFS_LASTSTORE);
  	ConvertWToSLock(&vcp->lock);
      }
      code = afs_CheckCode(code, &treq, 54);
      ReleaseSharedLock(&vcp->lock);
  
  out:
      AFS_GUNLOCK();
  
      crfree(credp);
--- 626,684 ----
  	return 0;
      }
  
+     AFS_DISCON_LOCK();
+ 
      credp = crref();
      vcp = VTOAFS(FILE_INODE(fp));
  
      code = afs_InitReq(&treq, credp);
      if (code)
  	goto out;
+ #if defined(AFS_CACHE_BYPASS)
+ 	/* If caching is bypassed for this file, or globally, just return 0 */
+ 	if(cache_bypass_strategy == ALWAYS_BYPASS_CACHE)
+ 		bypasscache = 1;
+ 	else {
+ 		ObtainReadLock(&vcp->lock);
+ 		if(vcp->cachingStates & FCSBypass)
+ 			bypasscache = 1;
+ 		ReleaseReadLock(&vcp->lock);
+ 	}
+ 	if(bypasscache) {
+             /* future proof: don't rely on 0 return from afs_InitReq */
+             code = 0; goto out;
+         }
+ #endif
  
      ObtainSharedLock(&vcp->lock, 535);
      if ((vcp->execsOrWriters > 0) && (file_count(fp) == 1)) {
  	UpgradeSToWLock(&vcp->lock, 536);
! 	if (!AFS_IS_DISCONNECTED) {
! 		code = afs_StoreAllSegments(vcp,
! 				&treq,
! 				AFS_SYNC | AFS_LASTSTORE);
! 	} else {
! #if defined(AFS_DISCON_ENV)
! 		if (!vcp->ddirty_flags ||
! 		    (vcp->ddirty_flags == VDisconShadowed)) {
! 
! 		    ObtainWriteLock(&afs_DDirtyVCListLock, 710);
! 		    AFS_DISCON_ADD_DIRTY(vcp);
! 		    ReleaseWriteLock(&afs_DDirtyVCListLock);
! 		}
! 
! 		/* Set disconnected write flag. */
! 		vcp->ddirty_flags |= VDisconWriteOsiFlush;
! #endif
! 	}
! 
  	ConvertWToSLock(&vcp->lock);
      }
      code = afs_CheckCode(code, &treq, 54);
      ReleaseSharedLock(&vcp->lock);
  
  out:
+     AFS_DISCON_UNLOCK();
      AFS_GUNLOCK();
  
      crfree(credp);
***************
*** 740,746 ****
      int code;
  
  #ifdef AFS_LINUX24_ENV
!     lock_kernel();
  #endif
      AFS_GLOCK();
  
--- 809,815 ----
      int code;
  
  #ifdef AFS_LINUX24_ENV
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
  
***************
*** 766,772 ****
  
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     unlock_kernel();
  #endif
      crfree(credp);
  
--- 835,841 ----
  
      AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     maybe_unlock_kernel();
  #endif
      crfree(credp);
  
***************
*** 809,815 ****
      int valid;
  
  #ifdef AFS_LINUX24_ENV
!     lock_kernel();
  #endif
      AFS_GLOCK();
  
--- 878,884 ----
      int valid;
  
  #ifdef AFS_LINUX24_ENV
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
  
***************
*** 897,903 ****
  	d_drop(dp);
      }
  #ifdef AFS_LINUX24_ENV
!     unlock_kernel();
  #endif
      return valid;
  
--- 966,972 ----
  	d_drop(dp);
      }
  #ifdef AFS_LINUX24_ENV
!     maybe_unlock_kernel();
  #endif
      return valid;
  
***************
*** 973,979 ****
      vattr.va_type = mode & S_IFMT;
  
  #if defined(AFS_LINUX26_ENV)
!     lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_create(VTOAFS(dip), (char *)name, &vattr, NONEXCL, mode,
--- 1042,1048 ----
      vattr.va_type = mode & S_IFMT;
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_create(VTOAFS(dip), (char *)name, &vattr, NONEXCL, mode,
***************
*** 992,998 ****
      AFS_GUNLOCK();
  
  #if defined(AFS_LINUX26_ENV)
!     unlock_kernel();
  #endif
      crfree(credp);
      return -code;
--- 1061,1067 ----
      AFS_GUNLOCK();
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_unlock_kernel();
  #endif
      crfree(credp);
      return -code;
***************
*** 1022,1028 ****
      int code;
  
  #if defined(AFS_LINUX26_ENV)
!     lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_lookup(VTOAFS(dip), comp, &vcp, credp);
--- 1091,1097 ----
      int code;
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_lock_kernel();
  #endif
      AFS_GLOCK();
      code = afs_lookup(VTOAFS(dip), comp, &vcp, credp);
***************
*** 1080,1086 ****
  #endif
  
  #if defined(AFS_LINUX26_ENV)
!     unlock_kernel();
  #endif
      crfree(credp);
  
--- 1149,1155 ----
  #endif
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_unlock_kernel();
  #endif
      crfree(credp);
  
***************
*** 1134,1140 ****
      struct vcache *tvc = VTOAFS(dp->d_inode);
  
  #if defined(AFS_LINUX26_ENV)
!     lock_kernel();
  #endif
      if (VREFCOUNT(tvc) > 1 && tvc->opens > 0
  				&& !(tvc->states & CUnlinked)) {
--- 1203,1209 ----
      struct vcache *tvc = VTOAFS(dp->d_inode);
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_lock_kernel();
  #endif
      if (VREFCOUNT(tvc) > 1 && tvc->opens > 0
  				&& !(tvc->states & CUnlinked)) {
***************
*** 1199,1205 ****
  	d_drop(dp);
  out:
  #if defined(AFS_LINUX26_ENV)
!     unlock_kernel();
  #endif
      crfree(credp);
      return -code;
--- 1268,1274 ----
  	d_drop(dp);
  out:
  #if defined(AFS_LINUX26_ENV)
!     maybe_unlock_kernel();
  #endif
      crfree(credp);
      return -code;
***************
*** 1237,1243 ****
      const char *name = dp->d_name.name;
  
  #if defined(AFS_LINUX26_ENV)
!     lock_kernel();
  #endif
      VATTR_NULL(&vattr);
      vattr.va_mask = ATTR_MODE;
--- 1306,1312 ----
      const char *name = dp->d_name.name;
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_lock_kernel();
  #endif
      VATTR_NULL(&vattr);
      vattr.va_mask = ATTR_MODE;
***************
*** 1258,1264 ****
      AFS_GUNLOCK();
  
  #if defined(AFS_LINUX26_ENV)
!     unlock_kernel();
  #endif
      crfree(credp);
      return -code;
--- 1327,1333 ----
      AFS_GUNLOCK();
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_unlock_kernel();
  #endif
      crfree(credp);
      return -code;
***************
*** 1306,1312 ****
  
  #if defined(AFS_LINUX26_ENV)
      /* Prevent any new references during rename operation. */
!     lock_kernel();
  
      if (!d_unhashed(newdp)) {
  	d_drop(newdp);
--- 1375,1381 ----
  
  #if defined(AFS_LINUX26_ENV)
      /* Prevent any new references during rename operation. */
!     maybe_lock_kernel();
  
      if (!d_unhashed(newdp)) {
  	d_drop(newdp);
***************
*** 1335,1341 ****
  	d_rehash(rehash);
  
  #if defined(AFS_LINUX26_ENV)
!     unlock_kernel();
  #endif
  
      crfree(credp);
--- 1404,1410 ----
  	d_rehash(rehash);
  
  #if defined(AFS_LINUX26_ENV)
!     maybe_unlock_kernel();
  #endif
  
      crfree(credp);
***************
*** 1451,1544 ****
  #endif /* AFS_LINUX24_ENV */
  #endif /* USABLE_KERNEL_PAGE_SYMLINK_CACHE */
  
  /* afs_linux_readpage
   * all reads come through here. A strategy-like read call.
   */
  static int
  afs_linux_readpage(struct file *fp, struct page *pp)
  {
!     int code;
!     cred_t *credp = crref();
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
!     char *address;
!     afs_offs_t offset = ((loff_t) pp->index) << PAGE_CACHE_SHIFT;
  #else
!     ulong address = afs_linux_page_address(pp);
!     afs_offs_t offset = pageoff(pp);
  #endif
!     uio_t tuio;
!     struct iovec iovec;
!     struct inode *ip = FILE_INODE(fp);
!     int cnt = page_count(pp);
!     struct vcache *avc = VTOAFS(ip);
! 
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
!     address = kmap(pp);
!     ClearPageError(pp);
  #else
!     atomic_add(1, &pp->count);
!     set_bit(PG_locked, &pp->flags);	/* other bits? See mm.h */
!     clear_bit(PG_error, &pp->flags);
! #endif
  
!     setup_uio(&tuio, &iovec, (char *)address, offset, PAGE_SIZE, UIO_READ,
! 	      AFS_UIOSYS);
  #ifdef AFS_LINUX24_ENV
!     lock_kernel();
  #endif
!     AFS_GLOCK();
!     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32, 99999);	/* not a possible code value */
!     code = afs_rdwr(avc, &tuio, UIO_READ, 0, credp);
!     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip,
! 	       ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32,
! 	       code);
!     AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
!     unlock_kernel();
  #endif
  
-     if (!code) {
- 	if (tuio.uio_resid)	/* zero remainder of page */
- 	    memset((void *)(address + (PAGE_SIZE - tuio.uio_resid)), 0,
- 		   tuio.uio_resid);
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
! 	flush_dcache_page(pp);
! 	SetPageUptodate(pp);
  #else
! 	set_bit(PG_uptodate, &pp->flags);
  #endif
!     }
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
!     kunmap(pp);
!     UnlockPage(pp);
  #else
!     clear_bit(PG_locked, &pp->flags);
!     wake_up(&pp->wait);
!     free_page(address);
  #endif
  
!     if (!code && AFS_CHUNKOFFSET(offset) == 0) {
! 	struct dcache *tdc;
! 	struct vrequest treq;
  
! 	AFS_GLOCK();
! 	code = afs_InitReq(&treq, credp);
! 	if (!code && !NBObtainWriteLock(&avc->lock, 534)) {
! 	    tdc = afs_FindDCache(avc, offset);
! 	    if (tdc) {
! 		if (!(tdc->mflags & DFNextStarted))
! 		    afs_PrefetchChunk(avc, tdc, credp, &treq);
! 		afs_PutDCache(tdc);
! 	    }
! 	    ReleaseWriteLock(&avc->lock);
! 	}
! 	AFS_GUNLOCK();
!     }
  
!     crfree(credp);
!     return -code;
  }
  
  
--- 1520,1839 ----
  #endif /* AFS_LINUX24_ENV */
  #endif /* USABLE_KERNEL_PAGE_SYMLINK_CACHE */
  
+ #if defined(AFS_CACHE_BYPASS)
+ 
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ 
+ /* The kernel calls readpages before trying readpage, with a list of 
+  * pages.  The readahead algorithm expands num_pages when it thinks
+  * the application will benefit.  Unlike readpage, the pages are not
+  * necessarily allocated.  If we do not a) allocate required pages and 
+  * b) remove them from page_list, linux will re-enter at afs_linux_readpage
+  * for each required page (and the page will be pre-allocated) */	
+ 
+ static int
+ afs_linux_readpages(struct file *fp, struct address_space *mapping,
+ 		    struct list_head *page_list, unsigned num_pages)
+ {
+     afs_int32 page_ix;
+     uio_t *auio;
+     afs_offs_t offset;
+     struct iovec* iovecp;
+     struct nocache_read_request *ancr;
+     struct page *pp, *ppt;
+     struct pagevec lrupv;
+     afs_int32 code = 0;	
+ 
+     cred_t *credp;
+     struct inode *ip = FILE_INODE(fp);
+     struct vcache *avc = VTOAFS(ip);
+     afs_int32 bypasscache = 0; /* bypass for this read */
+     afs_int32 base_index = 0;
+     afs_int32 page_count = 0;
+     afs_int32 isize;
+ 	
+     credp = crref();
+ 	
+     switch(cache_bypass_strategy) {
+     case NEVER_BYPASS_CACHE:
+ 	break;	
+     case ALWAYS_BYPASS_CACHE:
+ 	bypasscache = 1;
+ 	break;
+     case LARGE_FILES_BYPASS_CACHE:
+ 	if(i_size_read(ip) > cache_bypass_threshold) {
+ 	    bypasscache = 1;
+ 	}
+ 	break;
+     default:
+ 	break;
+     }
+ 	
+     /* In the new incarnation of selective caching, a file's caching policy 
+      *  can change, eg because file size exceeds threshold, etc. */
+     trydo_cache_transition(avc, credp, bypasscache);	
+ 	 
+     if(!bypasscache) {
+ 	while(!list_empty(page_list)) {
+ 	    pp = list_entry(page_list->prev, struct page, lru);
+ 	    list_del(&pp->lru);
+ 	}
+ 	goto out;
+     }
+     /* background thread must free: iovecp, auio, ancr */
+     iovecp = osi_Alloc(num_pages * sizeof(struct iovec));
+ 
+     auio = osi_Alloc(sizeof(uio_t));
+     auio->uio_iov = iovecp;	
+     auio->uio_iovcnt = num_pages;
+     auio->uio_flag = UIO_READ;
+     auio->uio_seg = AFS_UIOSYS;
+     auio->uio_resid = num_pages * PAGE_SIZE;
+ 	
+     ancr = osi_Alloc(sizeof(struct nocache_read_request));
+     ancr->auio = auio;
+     ancr->offset = auio->uio_offset;
+     ancr->length = auio->uio_resid;
+ 	
+     pagevec_init(&lrupv, 0);	
+ 	
+     for(page_ix = 0; page_ix < num_pages; ++page_ix) {
+ 	
+ 	if(list_empty(page_list))
+ 	    break;
+ 
+ 	pp = list_entry(page_list->prev, struct page, lru);
+ 	/* If we allocate a page and don't remove it from page_list,
+ 	 * the page cache gets upset. */
+ 	list_del(&pp->lru);
+ 	isize = (i_size_read(fp->f_mapping->host) - 1) >> PAGE_CACHE_SHIFT;
+ 	if(pp->index > isize) {
+ 	    if(PageLocked(pp))
+ 		UnlockPage(pp);
+ 	    continue;
+ 	}
+ 
+ 	if(page_ix == 0) {
+ 	    offset = ((loff_t) pp->index) << PAGE_CACHE_SHIFT;
+ 	    auio->uio_offset = offset;
+ 	    base_index = pp->index;
+ 	}
+         iovecp[page_ix].iov_len = PAGE_SIZE;
+         code = add_to_page_cache(pp, mapping, pp->index, GFP_KERNEL);
+         if(base_index != pp->index) {   
+             if(PageLocked(pp))
+ 				 UnlockPage(pp);
+             page_cache_release(pp);
+ 	    iovecp[page_ix].iov_base = (void *) 0;
+ 	    base_index++;
+             continue;
+         }
+         base_index++;
+         if(code) {
+ 	    if(PageLocked(pp))
+ 		UnlockPage(pp);
+ 	    page_cache_release(pp);
+ 	    iovecp[page_ix].iov_base = (void *) 0;
+ 	} else {
+ 	    page_count++;
+ 	    if(!PageLocked(pp)) {
+ 		LockPage(pp);
+ 	    }	
+ 	    
+ 	    /* save the page for background map */
+             iovecp[page_ix].iov_base = (void*) pp;
+ 
+ 	    /* and put it on the LRU cache */
+ 	    if (!pagevec_add(&lrupv, pp))
+ 		__pagevec_lru_add(&lrupv);
+         }
+     }
+ 
+     /* If there were useful pages in the page list, make sure all pages
+      * are in the LRU cache, then schedule the read */
+     if(page_count) {
+         pagevec_lru_add(&lrupv);
+         code = afs_ReadNoCache(avc, ancr, credp);
+     } else {
+         /* If there is nothing for the background thread to handle,
+          * it won't be freeing the things that we never gave it */
+         osi_Free(iovecp, num_pages * sizeof(struct iovec));
+         osi_Free(auio, sizeof(uio_t));
+         osi_Free(ancr, sizeof(struct nocache_read_request));
+     }
+     /* we do not flush, release, or unmap pages--that will be 
+      * done for us by the background thread as each page comes in
+      * from the fileserver */
+     crfree(credp);
+ 	
+ out:	
+     return -code;
+ }
+ 
+ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
+ #endif /* defined(AFS_CACHE_BYPASS */
+ 
+ 
  /* afs_linux_readpage
   * all reads come through here. A strategy-like read call.
   */
  static int
  afs_linux_readpage(struct file *fp, struct page *pp)
  {
! 	 afs_int32 code;
! 	 cred_t *credp = crref();
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
! 	 char *address;
! 	 afs_offs_t offset = ((loff_t) pp->index) << PAGE_CACHE_SHIFT;
  #else
! 	 ulong address = afs_linux_page_address(pp);
! 	 afs_offs_t offset = pageoff(pp);
  #endif
! #if defined(AFS_CACHE_BYPASS)
! 	 afs_int32 bypasscache = 0; /* bypass for this read */
! 	 struct nocache_read_request *ancr;
! #endif
! 	 afs_int32 isize;	
! 	 uio_t *auio;
! 	 struct iovec *iovecp;
! 	 struct inode *ip = FILE_INODE(fp);
! 	 afs_int32 cnt = page_count(pp);
! 	 struct vcache *avc = VTOAFS(ip);
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
! 	 address = kmap(pp);
! 	 ClearPageError(pp);
  #else
! 	 atomic_add(1, &pp->count);
! 	 set_bit(PG_locked, &pp->flags);	/* other bits? See mm.h */
! 	 clear_bit(PG_error, &pp->flags);
! #endif
! 	 /* If the page is past the end of the file, skip it */
! 	 isize = (i_size_read(fp->f_mapping->host) - 1) >> PAGE_CACHE_SHIFT;
! 	 if(pp->index > isize) {
! 		  if(PageLocked(pp))
! 			   UnlockPage(pp);
! 		  goto done;
! 	 }
! 	 /* if bypasscache, receiver frees, else we do */
! 	 auio = osi_Alloc(sizeof(uio_t));
! 	 iovecp = osi_Alloc(sizeof(struct iovec));
! 	
! 	 setup_uio(auio, iovecp, (char *)address, offset, PAGE_SIZE, UIO_READ,
! 			   AFS_UIOSYS);
  
! #if defined(AFS_CACHE_BYPASS)
! 
! 	 switch(cache_bypass_strategy) {
! 	 case NEVER_BYPASS_CACHE:
! 		  break;	
! 	 case ALWAYS_BYPASS_CACHE:
! 		  bypasscache = 1;
! 		  break;
! 	 case LARGE_FILES_BYPASS_CACHE:
! 		  if(i_size_read(ip) > cache_bypass_threshold) {
! 			   bypasscache = 1;
! 		  }
! 		  break;
! 	 default:
! 		  break;
! 	 }
! 
! 	 /* In the new incarnation of selective caching, a file's caching policy 
! 	  * can change, eg because file size exceeds threshold, etc. */
! 	 trydo_cache_transition(avc, credp, bypasscache);
! 		
! 	 if(bypasscache) {
! 		  if(address)
! 			   kunmap(pp);
! 		  /* save the page for background map */
! 		  auio->uio_iov->iov_base = (void*) pp;
! 		  /* the background thread will free this */
! 		  ancr = osi_Alloc(sizeof(struct nocache_read_request));
! 		  ancr->auio = auio;
! 		  ancr->offset = offset;
! 		  ancr->length = PAGE_SIZE;
! 	
! 		  maybe_lock_kernel();
! 		  code = afs_ReadNoCache(avc, ancr, credp);
! 		  maybe_unlock_kernel();
! 	
! 		  goto done; /* skips release page, doing it in bg thread */
! 	 }
! #endif 
! 		  
  #ifdef AFS_LINUX24_ENV
! 	 maybe_lock_kernel();
  #endif
! 	 AFS_GLOCK();
! 	 afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32, 99999);	/* not a possible code value */
! 
! 	 code = afs_rdwr(avc, auio, UIO_READ, 0, credp);
! 	
! 	 afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip,
! 				ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32,
! 				code);
! 	 AFS_GUNLOCK();
  #ifdef AFS_LINUX24_ENV
! 	 maybe_unlock_kernel();
  #endif
+ 	 if (!code) {	
+ 		  /* XXX valid for no-cache also?  Check last bits of files... :) 
+ 		   * Cognate code goes in afs_NoCacheFetchProc.  */
+ 		  if (auio->uio_resid)	/* zero remainder of page */
+ 			   memset((void *)(address + (PAGE_SIZE - auio->uio_resid)), 0,
+ 					  auio->uio_resid);
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
! 		  flush_dcache_page(pp);
! 		  SetPageUptodate(pp);
  #else
! 		  set_bit(PG_uptodate, &pp->flags);
  #endif
! 	 } /* !code */
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
! 	 kunmap(pp);
! 	 UnlockPage(pp);
  #else
! 	 clear_bit(PG_locked, &pp->flags);
! 	 wake_up(&pp->wait);
! 	 free_page(address);
  #endif
  
! #if defined(AFS_CACHE_BYPASS)
  
! /* do not call afs_GetDCache if cache is bypassed */
! 	 if(bypasscache)
! 		  goto done;
! 	
! #endif
  
! 	 /* free if not bypassing cache */
! 	 osi_Free(auio, sizeof(uio_t));
! 	 osi_Free(iovecp, sizeof(struct iovec));
! 
! 	 if (!code && AFS_CHUNKOFFSET(offset) == 0) {
! 		  struct dcache *tdc;
! 		  struct vrequest treq;
! 
! 		  AFS_GLOCK();
! 		  code = afs_InitReq(&treq, credp);
! 		  if (!code && !NBObtainWriteLock(&avc->lock, 534)) {
! 			   tdc = afs_FindDCache(avc, offset);
! 			   if (tdc) {
! 					if (!(tdc->mflags & DFNextStarted))
! 						 afs_PrefetchChunk(avc, tdc, credp, &treq);
! 					afs_PutDCache(tdc);
! 			   }
! 			   ReleaseWriteLock(&avc->lock);
! 		  }
! 		  AFS_GUNLOCK();
! 	 }
! 
! done:
! 	 crfree(credp);
! 	 return -code;
  }
  
  
***************
*** 1560,1566 ****
      base = (((loff_t) pp->index) << PAGE_CACHE_SHIFT)  + offset;
  
      credp = crref();
!     lock_kernel();
      AFS_GLOCK();
      afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
  	       ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
--- 1855,1861 ----
      base = (((loff_t) pp->index) << PAGE_CACHE_SHIFT)  + offset;
  
      credp = crref();
!     maybe_lock_kernel();
      AFS_GLOCK();
      afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
  	       ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
***************
*** 1588,1594 ****
  	       ICL_TYPE_INT32, code);
  
      AFS_GUNLOCK();
!     unlock_kernel();
      crfree(credp);
      kunmap(pp);
  
--- 1883,1889 ----
  	       ICL_TYPE_INT32, code);
  
      AFS_GUNLOCK();
!     maybe_unlock_kernel();
      crfree(credp);
      kunmap(pp);
  
***************
*** 1769,1775 ****
    .setattr =		afs_notify_change,
  #else
    .default_file_ops =	&afs_file_fops,
!   .readpage =		afs_linux_readpage,
    .revalidate =		afs_linux_revalidate,
    .updatepage =		afs_linux_updatepage,
  #endif
--- 2064,2070 ----
    .setattr =		afs_notify_change,
  #else
    .default_file_ops =	&afs_file_fops,
!   .readpage =		afs_linux_readpage,  
    .revalidate =		afs_linux_revalidate,
    .updatepage =		afs_linux_updatepage,
  #endif
***************
*** 1778,1783 ****
--- 2073,2081 ----
  #if defined(AFS_LINUX24_ENV)
  static struct address_space_operations afs_file_aops = {
    .readpage =		afs_linux_readpage,
+ #if defined(AFS_CACHE_BYPASS) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+   .readpages =		afs_linux_readpages,
+ #endif  
    .writepage =		afs_linux_writepage,
    .commit_write =	afs_linux_commit_write,
    .prepare_write =	afs_linux_prepare_write,
***************
*** 1822,1828 ****
      char *p = (char *)kmap(page);
      int code;
  
!     lock_kernel();
      AFS_GLOCK();
      code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
      AFS_GUNLOCK();
--- 2120,2126 ----
      char *p = (char *)kmap(page);
      int code;
  
!     maybe_lock_kernel();
      AFS_GLOCK();
      code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
      AFS_GUNLOCK();
***************
*** 1830,1836 ****
      if (code < 0)
  	goto fail;
      p[code] = '\0';		/* null terminate? */
!     unlock_kernel();
  
      SetPageUptodate(page);
      kunmap(page);
--- 2128,2134 ----
      if (code < 0)
  	goto fail;
      p[code] = '\0';		/* null terminate? */
!     maybe_unlock_kernel();
  
      SetPageUptodate(page);
      kunmap(page);
***************
*** 1838,1844 ****
      return 0;
  
    fail:
!     unlock_kernel();
  
      SetPageError(page);
      kunmap(page);
--- 2136,2142 ----
      return 0;
  
    fail:
!     maybe_unlock_kernel();
  
      SetPageError(page);
      kunmap(page);
Index: openafs/src/afs/VNOPS/afs_vnop_access.c
diff -c openafs/src/afs/VNOPS/afs_vnop_access.c:1.11.8.6 openafs/src/afs/VNOPS/afs_vnop_access.c:1.11.8.7
*** openafs/src/afs/VNOPS/afs_vnop_access.c:1.11.8.6	Fri May 23 10:25:16 2008
--- openafs/src/afs/VNOPS/afs_vnop_access.c	Mon Sep 22 15:29:55 2008
***************
*** 23,29 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_access.c,v 1.11.8.6 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 23,29 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_access.c,v 1.11.8.7 2008/09/22 19:29:55 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 246,255 ****
      }
      
      /* If we're looking for write access, and we're disconnected without logging, forget it */
!     if ((amode & VWRITE) && (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING)) {
          afs_PutFakeStat(&fakestate);
  	AFS_DISCON_UNLOCK();
! 	/*printf("Network is down in afs_vnop_access\n");*/
          return ENETDOWN;
      }
      
--- 246,255 ----
      }
      
      /* If we're looking for write access, and we're disconnected without logging, forget it */
!     if ((amode & VWRITE) && (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW)) {
          afs_PutFakeStat(&fakestate);
  	AFS_DISCON_UNLOCK();
! 	printf("Network is down in afs_vnop_access\n");
          return ENETDOWN;
      }
      
Index: openafs/src/afs/VNOPS/afs_vnop_attrs.c
diff -c openafs/src/afs/VNOPS/afs_vnop_attrs.c:1.41.2.2 openafs/src/afs/VNOPS/afs_vnop_attrs.c:1.41.2.3
*** openafs/src/afs/VNOPS/afs_vnop_attrs.c:1.41.2.2	Fri May 23 10:25:16 2008
--- openafs/src/afs/VNOPS/afs_vnop_attrs.c	Mon Sep 22 15:29:55 2008
***************
*** 24,30 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_attrs.c,v 1.41.2.2 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 24,30 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_attrs.c,v 1.41.2.3 2008/09/22 19:29:55 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 40,45 ****
--- 40,46 ----
  extern struct vfs *afs_globalVFS;
  #endif
  
+ 
  /* copy out attributes from cache entry */
  int
  afs_CopyOutAttrs(register struct vcache *avc, register struct vattr *attrs)
***************
*** 509,515 ****
  	}
      }
  
!     if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
          code = ENETDOWN;
          goto done;
      }
--- 510,516 ----
  	}
      }
  
!     if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
          code = ENETDOWN;
          goto done;
      }
***************
*** 542,547 ****
--- 543,549 ----
  	afs_size_t tsize = attrs->va_size;
  	ObtainWriteLock(&avc->lock, 128);
  	avc->states |= CDirty;
+ 
  	code = afs_TruncateAllSegments(avc, tsize, &treq, acred);
  	/* if date not explicitly set by this call, set it ourselves, since we
  	 * changed the data */
***************
*** 549,560 ****
  	    astat.Mask |= AFS_SETMODTIME;
  	    astat.ClientModTime = osi_Time();
  	}
  	if (code == 0) {
  	    if (((avc->execsOrWriters <= 0) && (avc->states & CCreating) == 0)
  		|| (avc->execsOrWriters == 1 && AFS_NFSXLATORREQ(acred))) {
! 		code = afs_StoreAllSegments(avc, &treq, AFS_ASYNC);
! 		if (!code)
! 		    avc->states &= ~CDirty;
  	    }
  	} else
  	    avc->states &= ~CDirty;
--- 551,568 ----
  	    astat.Mask |= AFS_SETMODTIME;
  	    astat.ClientModTime = osi_Time();
  	}
+ 
  	if (code == 0) {
  	    if (((avc->execsOrWriters <= 0) && (avc->states & CCreating) == 0)
  		|| (avc->execsOrWriters == 1 && AFS_NFSXLATORREQ(acred))) {
! 
! 		/* Store files now if not disconnected. */
! 		/* XXX: AFS_IS_DISCON_RW handled. */
! 		if (!AFS_IS_DISCONNECTED) {
! 			code = afs_StoreAllSegments(avc, &treq, AFS_ASYNC);
! 			if (!code)
! 		    		avc->states &= ~CDirty;
! 		}
  	    }
  	} else
  	    avc->states &= ~CDirty;
***************
*** 579,588 ****
  	        osi_dnlc_purgedp(avc);
  	    /* error?  erase any changes we made to vcache entry */
          }
      } else {
!         /* Must be logging - but not implemented yet ... */
!         code = ENETDOWN;
!     }
  #if	defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
      if (AFS_NFSXLATORREQ(acred)) {
  	avc->execsOrWriters--;
--- 587,603 ----
  	        osi_dnlc_purgedp(avc);
  	    /* error?  erase any changes we made to vcache entry */
          }
+ 
+ #if defined(AFS_DISCON_ENV)
      } else {
! 
! 	ObtainSharedLock(&avc->lock, 712);
! 	/* Write changes locally. */
! 	code = afs_WriteVCacheDiscon(avc, &astat, attrs);
! 	ReleaseSharedLock(&avc->lock);
! #endif
!     }		/* if (!AFS_IS_DISCONNECTED) */
! 
  #if	defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
      if (AFS_NFSXLATORREQ(acred)) {
  	avc->execsOrWriters--;
Index: openafs/src/afs/VNOPS/afs_vnop_create.c
diff -c openafs/src/afs/VNOPS/afs_vnop_create.c:1.23.4.4 openafs/src/afs/VNOPS/afs_vnop_create.c:1.23.4.6
*** openafs/src/afs/VNOPS/afs_vnop_create.c:1.23.4.4	Fri May 23 10:25:16 2008
--- openafs/src/afs/VNOPS/afs_vnop_create.c	Thu Sep 25 05:02:56 2008
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_create.c,v 1.23.4.4 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 17,23 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_create.c,v 1.23.4.6 2008/09/25 09:02:56 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 122,128 ****
  	goto done;
      }
  
!     if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
          code = ENETDOWN;
          goto done;
      }
--- 122,128 ----
  	goto done;
      }
  
!     if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
          code = ENETDOWN;
          goto done;
      }
***************
*** 260,270 ****
  	}
      }
      
-     if (AFS_IS_DISCONNECTED) {
-         /* XXX - If we get here, logging must be enabled (as we bypassed the
-          * earlier check. So - do that logging thang, then return */
-     }       
- 
      /* if we create the file, we don't do any access checks, since
       * that's how O_CREAT is supposed to work */
      if (adp->states & CForeign) {
--- 260,265 ----
***************
*** 296,369 ****
  		attrs->va_mode = 0x1b6;	/* XXX default mode: rw-rw-rw XXX */
  	}
      }
!     InStatus.UnixModeBits = attrs->va_mode & 0xffff;	/* only care about protection bits */
!     do {
! 	tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
! 	if (tc) {
! 	    hostp = tc->srvr->server;	/* remember for callback processing */
! 	    now = osi_Time();
! 	    XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
! 	    RX_AFS_GUNLOCK();
! 	    code =
! 		RXAFS_CreateFile(tc->id, (struct AFSFid *)&adp->fid.Fid,
  				 aname, &InStatus, (struct AFSFid *)
  				 &newFid.Fid, &OutFidStatus, &OutDirStatus,
  				 &CallBack, &tsync);
! 	    RX_AFS_GLOCK();
! 	    XSTATS_END_TIME;
! 	    CallBack.ExpirationTime += now;
! 	} else
! 	    code = -1;
!     } while (afs_Analyze
! 	     (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
! 	      SHARED_LOCK, NULL));
  
!     if ((code == EEXIST || code == UAEEXIST) &&
  #ifdef AFS_SGI64_ENV
!     !(flags & VEXCL)
  #else /* AFS_SGI64_ENV */
!     aexcl == NONEXCL
  #endif
!     ) {
! 	/* if we get an EEXIST in nonexcl mode, just do a lookup */
! 	if (tdc) {
! 	    ReleaseSharedLock(&tdc->lock);
! 	    afs_PutDCache(tdc);
! 	}
! 	ReleaseWriteLock(&adp->lock);
  #if !(defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV))
  #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
  #if defined(AFS_SGI64_ENV)
! 	code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp, 
! 			  NULL, 0, NULL, acred);
  #else
! 	code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
  #endif /* AFS_SGI64_ENV */
  #else /* SUN5 || SGI */
! 	code = afs_lookup(adp, aname, avcp, acred);
  #endif /* SUN5 || SGI */
  #endif /* !(AFS_OSF_ENV || AFS_DARWIN_ENV) */
  	goto done;
!     }
!     if (code) {
! 	if (code < 0) {
! 	    ObtainWriteLock(&afs_xcbhash, 488);
! 	    afs_DequeueCallback(adp);
! 	    adp->states &= ~CStatd;
! 	    ReleaseWriteLock(&afs_xcbhash);
! 	    osi_dnlc_purgedp(adp);
! 	}
! 	ReleaseWriteLock(&adp->lock);
! 	if (tdc) {
! 	    ReleaseSharedLock(&tdc->lock);
! 	    afs_PutDCache(tdc);
! 	}
  	goto done;
!     }
      /* otherwise, we should see if we can make the change to the dir locally */
      if (tdc)
  	UpgradeSToWLock(&tdc->lock, 631);
!     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
  	/* we can do it locally */
  	ObtainWriteLock(&afs_xdcache, 291);
  	code = afs_dir_Create(tdc, aname, &newFid.Fid);
--- 291,379 ----
  		attrs->va_mode = 0x1b6;	/* XXX default mode: rw-rw-rw XXX */
  	}
      }
! 
!     if (!AFS_IS_DISCONNECTED) {
! 	/* If not disconnected, connect to the server.*/
! 
!     	InStatus.UnixModeBits = attrs->va_mode & 0xffff;	/* only care about protection bits */
!     	do {
! 	    tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
! 	    if (tc) {
! 	    	hostp = tc->srvr->server;	/* remember for callback processing */
! 	    	now = osi_Time();
! 	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
! 	    	RX_AFS_GUNLOCK();
! 	    	code =
! 		    RXAFS_CreateFile(tc->id, (struct AFSFid *)&adp->fid.Fid,
  				 aname, &InStatus, (struct AFSFid *)
  				 &newFid.Fid, &OutFidStatus, &OutDirStatus,
  				 &CallBack, &tsync);
! 	    	RX_AFS_GLOCK();
! 	    	XSTATS_END_TIME;
! 	    	CallBack.ExpirationTime += now;
! 	    } else
! 	    	code = -1;
!     	} while (afs_Analyze
! 	         (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
! 	          SHARED_LOCK, NULL));
  
! 	if ((code == EEXIST || code == UAEEXIST) &&
  #ifdef AFS_SGI64_ENV
!     	!(flags & VEXCL)
  #else /* AFS_SGI64_ENV */
!     	aexcl == NONEXCL
  #endif
!     	) {
! 	    /* if we get an EEXIST in nonexcl mode, just do a lookup */
! 	    if (tdc) {
! 	    	ReleaseSharedLock(&tdc->lock);
! 	    	afs_PutDCache(tdc);
! 	    }
! 	    ReleaseWriteLock(&adp->lock);
  #if !(defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV))
  #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
  #if defined(AFS_SGI64_ENV)
! 	    code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp,
! 				  NULL, 0, NULL, acred);
  #else
! 	    code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
  #endif /* AFS_SGI64_ENV */
  #else /* SUN5 || SGI */
! 	    code = afs_lookup(adp, aname, avcp, acred);
  #endif /* SUN5 || SGI */
  #endif /* !(AFS_OSF_ENV || AFS_DARWIN_ENV) */
  	goto done;
!         }
! 
! 	if (code) {
! 	    if (code < 0) {
! 	    	ObtainWriteLock(&afs_xcbhash, 488);
! 	    	afs_DequeueCallback(adp);
! 	    	adp->states &= ~CStatd;
! 	    	ReleaseWriteLock(&afs_xcbhash);
! 	    	osi_dnlc_purgedp(adp);
! 	    }
! 	    ReleaseWriteLock(&adp->lock);
! 	    if (tdc) {
! 	    	ReleaseSharedLock(&tdc->lock);
! 	    	afs_PutDCache(tdc);
! 	    }
  	goto done;
! 	}
! 
!     } else {
! #if defined(AFS_DISCON_ENV)
! 	/* Generate a fake FID for disconnected mode. */
! 	newFid.Cell = adp->fid.Cell;
! 	newFid.Fid.Volume = adp->fid.Fid.Volume;
! 	afs_GenFakeFid(&newFid, VREG);
! #endif
!     }				/* if (!AFS_IS_DISCON_RW) */
! 
      /* otherwise, we should see if we can make the change to the dir locally */
      if (tdc)
  	UpgradeSToWLock(&tdc->lock, 631);
!     if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
  	/* we can do it locally */
  	ObtainWriteLock(&afs_xdcache, 291);
  	code = afs_dir_Create(tdc, aname, &newFid.Fid);
***************
*** 436,447 ****
  		    osi_dnlc_purgedp(tvc);
  	    }
  	    ReleaseWriteLock(&afs_xcbhash);
! 	    afs_ProcessFS(tvc, &OutFidStatus, &treq);
  	    tvc->parentVnode = adp->fid.Fid.Vnode;
  	    tvc->parentUnique = adp->fid.Fid.Unique;
  	    ReleaseWriteLock(&tvc->lock);
  	    *avcp = tvc;
  	    code = 0;
  	} else
  	    code = ENOENT;
      } else {
--- 446,481 ----
  		    osi_dnlc_purgedp(tvc);
  	    }
  	    ReleaseWriteLock(&afs_xcbhash);
! 	    if (!AFS_IS_DISCON_RW)
! 	    	afs_ProcessFS(tvc, &OutFidStatus, &treq);
  	    tvc->parentVnode = adp->fid.Fid.Vnode;
  	    tvc->parentUnique = adp->fid.Fid.Unique;
  	    ReleaseWriteLock(&tvc->lock);
  	    *avcp = tvc;
  	    code = 0;
+ 
+ 	    if (AFS_IS_DISCON_RW) {
+ #if defined(AFS_DISCON_ENV)
+ 	    	/* After tvc has been created, we can do various ops on it. */
+ 		/* Add to dirty list. */
+ 		if (!tvc->ddirty_flags ||
+ 			(tvc->ddirty_flags == VDisconShadowed)) {
+ 	    	    /* Put it in the list only if it's fresh. */
+ 	    	    ObtainWriteLock(&afs_DDirtyVCListLock, 729);
+ 	    	    AFS_DISCON_ADD_DIRTY(tvc);
+ 	    	    ReleaseWriteLock(&afs_DDirtyVCListLock);
+ 		}
+ 
+ 		/* Set create flag. */
+ 		ObtainWriteLock(&tvc->lock, 730);
+ 		afs_GenDisconStatus(adp, tvc, &newFid, attrs, &treq, VREG);
+ 		tvc->ddirty_flags |= VDisconCreate;
+ 		ReleaseWriteLock(&tvc->lock);
+ 
+ #endif				/* #ifdef AFS_DISCON_ENV */
+     	    }			/* if (AFS_IS_DISCON_RW) */
+ 
+ 
  	} else
  	    code = ENOENT;
      } else {
Index: openafs/src/afs/VNOPS/afs_vnop_dirops.c
diff -c openafs/src/afs/VNOPS/afs_vnop_dirops.c:1.21.4.2 openafs/src/afs/VNOPS/afs_vnop_dirops.c:1.21.4.3
*** openafs/src/afs/VNOPS/afs_vnop_dirops.c:1.21.4.2	Fri May 23 10:25:16 2008
--- openafs/src/afs/VNOPS/afs_vnop_dirops.c	Mon Sep 22 15:29:55 2008
***************
*** 21,27 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_dirops.c,v 1.21.4.2 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 21,27 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_dirops.c,v 1.21.4.3 2008/09/22 19:29:55 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 44,49 ****
--- 44,50 ----
      register struct conn *tc;
      struct VenusFid newFid;
      register struct dcache *tdc;
+     struct dcache *new_dc;
      afs_size_t offset, len;
      register struct vcache *tvc;
      struct AFSStoreStatus InStatus;
***************
*** 90,144 ****
  	goto done;
      }
     
!     if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
  	/*printf("Network is down in afs_mkdir\n");*/
  	code = ENETDOWN;
-     }
- 
      InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
      InStatus.ClientModTime = osi_Time();
      InStatus.UnixModeBits = attrs->va_mode & 0xffff;	/* only care about protection bits */
      InStatus.Group = (afs_int32) acred->cr_gid;
      tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
      ObtainWriteLock(&adp->lock, 153);
!     do {
! 	tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
! 	if (tc) {
! 	    XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
! 	    now = osi_Time();
! 	    RX_AFS_GUNLOCK();
! 	    code =
! 		RXAFS_MakeDir(tc->id, (struct AFSFid *)&adp->fid.Fid, aname,
! 			      &InStatus, (struct AFSFid *)&newFid.Fid,
! 			      &OutFidStatus, &OutDirStatus, &CallBack,
! 			      &tsync);
! 	    RX_AFS_GLOCK();
! 	    XSTATS_END_TIME;
! 	    CallBack.ExpirationTime += now;
! 	    /* DON'T forget to Set the callback value... */
! 	} else
! 	    code = -1;
!     } while (afs_Analyze
! 	     (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_MAKEDIR,
! 	      SHARED_LOCK, NULL));
! 
!     if (code) {
! 	if (code < 0) {
! 	    ObtainWriteLock(&afs_xcbhash, 490);
! 	    afs_DequeueCallback(adp);
! 	    adp->states &= ~CStatd;
! 	    ReleaseWriteLock(&afs_xcbhash);
! 	    osi_dnlc_purgedp(adp);
! 	}
! 	ReleaseWriteLock(&adp->lock);
! 	if (tdc)
! 	    afs_PutDCache(tdc);
! 	goto done;
!     }
      /* otherwise, we should see if we can make the change to the dir locally */
      if (tdc)
  	ObtainWriteLock(&tdc->lock, 632);
!     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
  	/* we can do it locally */
  	ObtainWriteLock(&afs_xdcache, 294);
  	code = afs_dir_Create(tdc, aname, &newFid.Fid);
--- 91,171 ----
  	goto done;
      }
     
!     if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW)
  	/*printf("Network is down in afs_mkdir\n");*/
  	code = ENETDOWN;
      InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
      InStatus.ClientModTime = osi_Time();
      InStatus.UnixModeBits = attrs->va_mode & 0xffff;	/* only care about protection bits */
      InStatus.Group = (afs_int32) acred->cr_gid;
      tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
      ObtainWriteLock(&adp->lock, 153);
! 
!     if (!AFS_IS_DISCON_RW) {
! 
!     	do {
! 	    tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
! 	    if (tc) {
! 	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
! 	    	now = osi_Time();
! 	    	RX_AFS_GUNLOCK();
! 	    	code =
! 		    RXAFS_MakeDir(tc->id,
! 		    		(struct AFSFid *)&adp->fid.Fid,
! 				aname,
! 				&InStatus,
! 				(struct AFSFid *)&newFid.Fid,
! 				&OutFidStatus,
! 				&OutDirStatus,
! 				&CallBack,
! 				&tsync);
! 	    	RX_AFS_GLOCK();
! 	    	XSTATS_END_TIME;
! 	    	CallBack.ExpirationTime += now;
! 	    	/* DON'T forget to Set the callback value... */
! 	    } else
! 	    	code = -1;
!     	} while (afs_Analyze
! 		    (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_MAKEDIR,
! 		     SHARED_LOCK, NULL));
! 
!     	if (code) {
! 	    if (code < 0) {
! 	    	ObtainWriteLock(&afs_xcbhash, 490);
! 	    	afs_DequeueCallback(adp);
! 	    	adp->states &= ~CStatd;
! 	    	ReleaseWriteLock(&afs_xcbhash);
! 	    	osi_dnlc_purgedp(adp);
! 	    }
! 	    ReleaseWriteLock(&adp->lock);
! 	    if (tdc)
! 	    	afs_PutDCache(tdc);
! 	    goto done;
!         }
! 
!     } else {
! #if defined(AFS_DISCON_ENV)
!     	/* Disconnected. */
! 
! 	/* We have the dir entry now, we can use it while disconnected. */
! 	if (adp->mvid == NULL) {
! 	    /* If not mount point, generate a new fid. */
! 	    newFid.Cell = adp->fid.Cell;
!     	    newFid.Fid.Volume = adp->fid.Fid.Volume;
! 	    afs_GenFakeFid(&newFid, VDIR);
! 	}
!     	/* XXX: If mount point???*/
! 
! 	/* Operations with the actual dir's cache entry are further
! 	 * down, where the dir entry gets created.
! 	 */
! #endif
!     }			/* if (!AFS_IS_DISCON_RW) */
! 
      /* otherwise, we should see if we can make the change to the dir locally */
      if (tdc)
  	ObtainWriteLock(&tdc->lock, 632);
!     if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
  	/* we can do it locally */
  	ObtainWriteLock(&afs_xdcache, 294);
  	code = afs_dir_Create(tdc, aname, &newFid.Fid);
***************
*** 152,168 ****
  	ReleaseWriteLock(&tdc->lock);
  	afs_PutDCache(tdc);
      }
!     adp->m.LinkCount = OutDirStatus.LinkCount;
      newFid.Cell = adp->fid.Cell;
      newFid.Fid.Volume = adp->fid.Fid.Volume;
      ReleaseWriteLock(&adp->lock);
!     /* now we're done with parent dir, create the real dir's cache entry */
!     tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);
!     if (tvc) {
! 	code = 0;
! 	*avcp = tvc;
!     } else
! 	code = ENOENT;
    done:
      AFS_DISCON_UNLOCK();
    done3:
--- 179,255 ----
  	ReleaseWriteLock(&tdc->lock);
  	afs_PutDCache(tdc);
      }
! 
!     if (AFS_IS_DISCON_RW)
! 	/* We will have to settle with the local link count. */
! 	adp->m.LinkCount++;
!     else
! 	adp->m.LinkCount = OutDirStatus.LinkCount;
      newFid.Cell = adp->fid.Cell;
      newFid.Fid.Volume = adp->fid.Fid.Volume;
      ReleaseWriteLock(&adp->lock);
!     if (AFS_IS_DISCON_RW) {
! #if defined(AFS_DISCON_ENV)
!     	/* When disconnected, we have to create the full dir here. */
! 
! 	/* Generate a new vcache and fill it. */
! 	tvc = afs_NewVCache(&newFid, NULL);
! 	if (tvc) {
! 	    code = 0;
! 	    *avcp = tvc;
! 	} else {
! 	    code = ENOENT;
! 	    goto done;
! 	}
! 
! 	ObtainWriteLock(&tvc->lock, 738);
! 	afs_GenDisconStatus(adp, tvc, &newFid, attrs, &treq, VDIR);
! 	ReleaseWriteLock(&tvc->lock);
! 
! 	/* And now make an empty dir, containing . and .. : */
! 	/* Get a new dcache for it first. */
! 	new_dc = afs_GetDCache(tvc, (afs_size_t) 0, &treq, &offset, &len, 1);
! 	if (!new_dc) {
! 	    printf("afs_mkdir: can't get new dcache for dir.\n");
! 	    code = ENOENT;
! 	    goto done;
! 	}
! 
! 	ObtainWriteLock(&afs_xdcache, 739);
! 	code = afs_dir_MakeDir(new_dc,
! 				(afs_int32 *) &newFid.Fid,
! 				(afs_int32) &adp->fid.Fid);
! 	ReleaseWriteLock(&afs_xdcache);
! 	if (code)
! 	    printf("afs_mkdir: afs_dirMakeDir code = %u\n", code);
! 
! 	/* Add to dirty list. */
! 	if (!tvc->ddirty_flags ||
! 		(tvc->ddirty_flags == VDisconShadowed)) {
! 
! 	    /* Put it in the list only if it's fresh. */
! 	    ObtainWriteLock(&afs_DDirtyVCListLock, 730);
! 	    AFS_DISCON_ADD_DIRTY(tvc);
! 	    ReleaseWriteLock(&afs_DDirtyVCListLock);
! 	}
! 
! 	ObtainWriteLock(&tvc->lock, 731);
! 	/* Update length in the vcache. */
! 	tvc->m.Length = new_dc->f.chunkBytes;
! 	/* Set create flag. */
! 	tvc->ddirty_flags |= VDisconCreate;
! 	ReleaseWriteLock(&tvc->lock);
! #endif				/* #ifdef AFS_DISCON_ENV */
!     } else {
!     	/* now we're done with parent dir, create the real dir's cache entry */
!     	tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);
!     	if (tvc) {
! 	    code = 0;
! 	    *avcp = tvc;
!     	} else
! 	    code = ENOENT;
!     }				/* if (AFS_DISCON_RW) */
! 
    done:
      AFS_DISCON_UNLOCK();
    done3:
***************
*** 226,236 ****
  	goto done;
      }
  
!     if (AFS_IS_DISCONNECTED && !AFS_IS_LOGGING) {
          code = ENETDOWN;
          goto done;
      }
!     
      tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);	/* test for error below */
      ObtainWriteLock(&adp->lock, 154);
      if (tdc)
--- 313,324 ----
  	goto done;
      }
  
!    if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
!     	/* Disconnected read only mode. */
          code = ENETDOWN;
          goto done;
      }
! 
      tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);	/* test for error below */
      ObtainWriteLock(&adp->lock, 154);
      if (tdc)
***************
*** 256,297 ****
  	}
      }
  
!     do {
! 	tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
! 	if (tc) {
! 	    XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
! 	    RX_AFS_GUNLOCK();
! 	    code =
! 		RXAFS_RemoveDir(tc->id, (struct AFSFid *)&adp->fid.Fid, aname,
! 				&OutDirStatus, &tsync);
! 	    RX_AFS_GLOCK();
! 	    XSTATS_END_TIME;
! 	} else
! 	    code = -1;
!     } while (afs_Analyze
! 	     (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_REMOVEDIR,
! 	      SHARED_LOCK, NULL));
  
!     if (code) {
! 	if (tdc) {
  	    ReleaseSharedLock(&tdc->lock);
! 	    afs_PutDCache(tdc);
  	}
! 	if (code < 0) {
! 	    ObtainWriteLock(&afs_xcbhash, 491);
! 	    afs_DequeueCallback(adp);
! 	    adp->states &= ~CStatd;
! 	    ReleaseWriteLock(&afs_xcbhash);
! 	    osi_dnlc_purgedp(adp);
  	}
! 	ReleaseWriteLock(&adp->lock);
! 	goto done;
!     }
!     /* here if rpc worked; update the in-core link count */
!     adp->m.LinkCount = OutDirStatus.LinkCount;
      if (tdc)
  	UpgradeSToWLock(&tdc->lock, 634);
!     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
  	/* we can do it locally */
  	code = afs_dir_Delete(tdc, aname);
  	if (code) {
--- 344,460 ----
  	}
      }
  
!     if (!AFS_IS_DISCON_RW) {
! 	/* Not disconnected, can connect to server. */
!     	do {
! 	    tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
! 	    if (tc) {
! 	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
! 	    	RX_AFS_GUNLOCK();
! 	    	code =
! 		    RXAFS_RemoveDir(tc->id,
! 		    		(struct AFSFid *)&adp->fid.Fid,
! 				aname,
! 				&OutDirStatus,
! 				&tsync);
! 	    	RX_AFS_GLOCK();
! 	    	XSTATS_END_TIME;
! 	    } else
! 	    	code = -1;
!     	} while (afs_Analyze
! 	         (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_REMOVEDIR,
! 	         SHARED_LOCK, NULL));
! 
!     	if (code) {
! 	    if (tdc) {
! 	    	ReleaseSharedLock(&tdc->lock);
! 	    	afs_PutDCache(tdc);
! 	    }
  
! 	    if (code < 0) {
! 	    	ObtainWriteLock(&afs_xcbhash, 491);
! 	    	afs_DequeueCallback(adp);
! 	    	adp->states &= ~CStatd;
! 	    	ReleaseWriteLock(&afs_xcbhash);
! 	    	osi_dnlc_purgedp(adp);
! 	    }
! 	    ReleaseWriteLock(&adp->lock);
! 	    goto done;
!     	}
! 
!     	/* here if rpc worked; update the in-core link count */
!     	adp->m.LinkCount = OutDirStatus.LinkCount;
! 
!     } else {
! #if defined(AFS_DISCON_ENV)
!     	/* Disconnected. */
! 
! 	if (!tvc) {
! 	    /* Find the vcache. */
! 	    struct VenusFid tfid;
! 
! 	    tfid.Cell = adp->fid.Cell;
! 	    tfid.Fid.Volume = adp->fid.Fid.Volume;
! 	    code = afs_dir_Lookup(tdc, aname, &tfid.Fid);
! 
! 	    ObtainSharedLock(&afs_xvcache, 764);
! 	    tvc = afs_FindVCache(&tfid, 0, 1 /* do xstats */ );
! 	    ReleaseSharedLock(&afs_xvcache);
! 
! 	    if (!tvc) {
! 		printf("afs_rmdir: Can't find dir's vcache!\n");
! 		ReleaseSharedLock(&tdc->lock);
! 		afs_PutDCache(tdc);	/* drop ref count */
!     		ReleaseWriteLock(&adp->lock);
! 	    	goto done;
! 	    }
! 	}
! 
! 	if (tvc->m.LinkCount > 2) {
! 	    /* This dir contains more than . and .., thus it can't be
! 	     * deleted.
! 	     */
  	    ReleaseSharedLock(&tdc->lock);
! 	    code = ENOTEMPTY;
! 	    goto done;
  	}
! 
!     	/* Make a shadow copy of the parent dir (if not done already).
! 	 * There's no need to make a shadow copy of the deleted directory
! 	 * because a dir must be empty in order to be rmdir'ed.
! 	 * If the deleted dir has no shadow, it means that it was empty.
! 	 */
! 	if (!(adp->ddirty_flags & VDisconShadowed)) {
! 	    /* If tdc available, then it is locked.
! 	     * afs_MakeShadowDir unlocks it.
! 	     */
! 	    if (tdc)
! 	    	ReleaseSharedLock(&tdc->lock);
! 	    afs_MakeShadowDir(adp);
! 	    if (tdc)
! 	    	ObtainSharedLock(&tdc->lock, 732);
  	}
! 
! 	if (!tvc->ddirty_flags ||
! 		(tvc->ddirty_flags == VDisconShadowed)) {
! 	    /* Put it in the list only if it's fresh or has only been shadowed. */
! 	    ObtainWriteLock(&afs_DDirtyVCListLock, 728);
! 	    AFS_DISCON_ADD_DIRTY(tvc);
! 	    ReleaseWriteLock(&afs_DDirtyVCListLock);
! 	}
! 
! 	/* Now add the vcache to the dirty list. */
! 	ObtainWriteLock(&tvc->lock, 727);
! 	tvc->ddirty_flags |= VDisconRemove;
! 	ReleaseWriteLock(&tvc->lock);
! 
! 	adp->m.LinkCount--;
! #endif				/* #ifdef AFS_DISCON_ENV */
!     }				/* if (!AFS_IS_DISCON_RW) */
! 
      if (tdc)
  	UpgradeSToWLock(&tdc->lock, 634);
!     if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
  	/* we can do it locally */
  	code = afs_dir_Delete(tdc, aname);
  	if (code) {
***************
*** 314,320 ****
  	ObtainWriteLock(&tvc->lock, 155);
  	tvc->states &= ~CUnique;	/* For the dfs xlator */
  	ReleaseWriteLock(&tvc->lock);
! 	afs_PutVCache(tvc);
      }
      ReleaseWriteLock(&adp->lock);
      /* don't worry about link count since dirs can not be hardlinked */
--- 477,485 ----
  	ObtainWriteLock(&tvc->lock, 155);
  	tvc->states &= ~CUnique;	/* For the dfs xlator */
  	ReleaseWriteLock(&tvc->lock);
! 	/* If disconnected, keep this vcache around for resync. */
! 	if (!AFS_IS_DISCON_RW)
! 	    afs_PutVCache(tvc);
      }
      ReleaseWriteLock(&adp->lock);
      /* don't worry about link count since dirs can not be hardlinked */
Index: openafs/src/afs/VNOPS/afs_vnop_lookup.c
diff -c openafs/src/afs/VNOPS/afs_vnop_lookup.c:1.72.2.7 openafs/src/afs/VNOPS/afs_vnop_lookup.c:1.72.2.9
*** openafs/src/afs/VNOPS/afs_vnop_lookup.c:1.72.2.7	Fri May 23 10:25:16 2008
--- openafs/src/afs/VNOPS/afs_vnop_lookup.c	Mon Sep 22 15:29:55 2008
***************
*** 18,24 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_lookup.c,v 1.72.2.7 2008/05/23 14:25:16 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 18,24 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_lookup.c,v 1.72.2.9 2008/09/22 19:29:55 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 1232,1239 ****
      afs_InitFakeStat(&fakestate);
  
      AFS_DISCON_LOCK();
- 
-     /*printf("Looking up %s\n", aname);*/
      
      if ((code = afs_InitReq(&treq, acred)))
  	goto done;
--- 1232,1237 ----
***************
*** 1431,1437 ****
--- 1429,1437 ----
      if (tvc) {
  	if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
  	    /* need read access on dir to stat non-directory / non-link */
+ #ifndef AFS_FBSD80_ENV
  	    afs_PutVCache(tvc);
+ #endif
  	    *avcp = NULL;
  	    code = EACCES;
  	    goto done;
***************
*** 1588,1594 ****
  
  	    /* if the vcache isn't usable, release it */
  	    if (tvc && !(tvc->states & CStatd)) {
! 		afs_PutVCache(tvc);
  		tvc = NULL;
  	    }
  	} else {
--- 1588,1596 ----
  
  	    /* if the vcache isn't usable, release it */
  	    if (tvc && !(tvc->states & CStatd)) {
! #ifndef  AFS_FBSD80_ENV
! 	      afs_PutVCache(tvc);
! #endif
  		tvc = NULL;
  	    }
  	} else {
***************
*** 1651,1657 ****
--- 1653,1661 ----
  		ReleaseWriteLock(&tvc->lock);
  
  		if (code) {
+ #ifndef AFS_FBSD80_ENV
  		    afs_PutVCache(tvc);
+ #endif
  		    if (tvolp)
  			afs_PutVolume(tvolp, WRITE_LOCK);
  		    goto done;
***************
*** 1673,1679 ****
--- 1677,1685 ----
  		    } else {
  			tvc = afs_GetVCache(tvc
