Index: openafs/src/WINNT/afsd/afsd_init.c
diff -c openafs/src/WINNT/afsd/afsd_init.c:1.79.2.38 openafs/src/WINNT/afsd/afsd_init.c:1.79.2.38.2.1
*** openafs/src/WINNT/afsd/afsd_init.c:1.79.2.38	Wed Mar 19 20:01:59 2008
--- openafs/src/WINNT/afsd/afsd_init.c	Sun Jun 22 22:50:08 2008
***************
*** 81,87 ****
  char cm_NetbiosName[MAX_NB_NAME_LENGTH] = "";
  
  char cm_CachePath[MAX_PATH];
- DWORD cm_CachePathLen;
  DWORD cm_ValidateCache = 1;
  
  BOOL reportSessionStartups = FALSE;
--- 81,86 ----
Index: openafs/src/WINNT/afsd/cm_btree.c
diff -c openafs/src/WINNT/afsd/cm_btree.c:1.1.2.14 openafs/src/WINNT/afsd/cm_btree.c:1.1.2.14.2.1
*** openafs/src/WINNT/afsd/cm_btree.c:1.1.2.14	Fri Feb 22 19:17:34 2008
--- openafs/src/WINNT/afsd/cm_btree.c	Sun Jun 22 22:52:04 2008
***************
*** 1341,1346 ****
--- 1341,1348 ----
      if (isdata(node)) {
          if ( getdatakey(node).name )
              free(getdatakey(node).name);
+ 	if ( getdatavalue(node).longname )
+ 	    free(getdatavalue(node).longname);
      } else {    /* data node */
          for ( i=1; i<=getfanout(B); i++ ) {
              if (getkey(node, i).name)
Index: openafs/src/WINNT/afsd/cm_buf.c
diff -c openafs/src/WINNT/afsd/cm_buf.c:1.31.2.38 openafs/src/WINNT/afsd/cm_buf.c:1.31.2.38.2.1
*** openafs/src/WINNT/afsd/cm_buf.c:1.31.2.38	Thu May  8 01:27:14 2008
--- openafs/src/WINNT/afsd/cm_buf.c	Sun Jun 22 23:02:06 2008
***************
*** 722,728 ****
  	 * because we aren't going to be able to write this data to the file
  	 * server.
  	 */
! 	if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BADFD){
  	    bp->flags &= ~CM_BUF_DIRTY;
  	    bp->flags |= CM_BUF_ERROR;
              bp->dirty_offset = 0;
--- 722,728 ----
  	 * because we aren't going to be able to write this data to the file
  	 * server.
  	 */
! 	if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BADFD || code == CM_ERROR_NOACCESS){
  	    bp->flags &= ~CM_BUF_DIRTY;
  	    bp->flags |= CM_BUF_ERROR;
              bp->dirty_offset = 0;
Index: openafs/src/WINNT/afsd/cm_freelance.c
diff -c openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.11 openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.11.2.1
*** openafs/src/WINNT/afsd/cm_freelance.c:1.33.2.11	Fri Apr 11 13:46:24 2008
--- openafs/src/WINNT/afsd/cm_freelance.c	Sun Jun 22 23:00:43 2008
***************
*** 419,424 ****
--- 419,425 ----
                       lscpp = &tscp->nextp, tscp = tscp->nextp) {
                      if (tscp == scp) {
                          *lscpp = scp->nextp;
+                         scp->nextp = NULL;
  			lock_ObtainWrite(&scp->rw);
                          scp->flags &= ~CM_SCACHEFLAG_INHASH;
  			lock_ReleaseWrite(&scp->rw);
Index: openafs/src/WINNT/afsd/cm_scache.c
diff -c openafs/src/WINNT/afsd/cm_scache.c:1.35.2.74 openafs/src/WINNT/afsd/cm_scache.c:1.35.2.74.2.2
*** openafs/src/WINNT/afsd/cm_scache.c:1.35.2.74	Mon Apr 14 18:44:03 2008
--- openafs/src/WINNT/afsd/cm_scache.c	Sun Jun 22 23:05:03 2008
***************
*** 47,67 ****
  /* must be called with cm_scacheLock write-locked! */
  void cm_AdjustScacheLRU(cm_scache_t *scp)
  {
!     if (scp == cm_data.scacheLRULastp)
!         cm_data.scacheLRULastp = (cm_scache_t *) osi_QPrev(&scp->q);
      osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
!     osi_QAdd((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
!     if (!cm_data.scacheLRULastp) 
!         cm_data.scacheLRULastp = scp;
  }
  
! /* call with scache write-locked and mutex held */
  void cm_RemoveSCacheFromHashTable(cm_scache_t *scp)
  {
      cm_scache_t **lscpp;
      cm_scache_t *tscp;
      int i;
  	
      if (scp->flags & CM_SCACHEFLAG_INHASH) {
  	/* hash it out first */
  	i = CM_SCACHE_HASH(&scp->fid);
--- 47,66 ----
  /* must be called with cm_scacheLock write-locked! */
  void cm_AdjustScacheLRU(cm_scache_t *scp)
  {
!     lock_AssertWrite(&cm_scacheLock);
      osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
!     osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
  }
  
! /* call with cm_scacheLock write-locked and scp rw held */
  void cm_RemoveSCacheFromHashTable(cm_scache_t *scp)
  {
      cm_scache_t **lscpp;
      cm_scache_t *tscp;
      int i;
  	
+     lock_AssertWrite(&cm_scacheLock);
+     lock_AssertWrite(&scp->rw);
      if (scp->flags & CM_SCACHEFLAG_INHASH) {
  	/* hash it out first */
  	i = CM_SCACHE_HASH(&scp->fid);
***************
*** 70,75 ****
--- 69,75 ----
  	     lscpp = &tscp->nextp, tscp = tscp->nextp) {
  	    if (tscp == scp) {
  		*lscpp = scp->nextp;
+                 scp->nextp = NULL;
  		scp->flags &= ~CM_SCACHEFLAG_INHASH;
  		break;
  	    }
***************
*** 95,101 ****
--- 95,103 ----
  	return -1;
      }
  
+     lock_ObtainWrite(&scp->rw);
      cm_RemoveSCacheFromHashTable(scp);
+     lock_ReleaseWrite(&scp->rw);
  
  #if 0
      if (flags & CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS) {
***************
*** 234,239 ****
--- 236,242 ----
      cm_scache_t *scp;
      int retry = 0;
  
+     lock_AssertWrite(&cm_scacheLock);
  #if 0
      /* first pass - look for deleted objects */
      for ( scp = cm_data.scacheLRULastp;
***************
*** 751,758 ****
          scp->dotdotFid.vnode=1;
          scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
          if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
!             scp->nextp=cm_data.scacheHashTablep[hash];
!             cm_data.scacheHashTablep[hash]=scp;
              scp->flags |= CM_SCACHEFLAG_INHASH;
          }
          scp->refCount = 1;
--- 754,761 ----
          scp->dotdotFid.vnode=1;
          scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
          if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
!             scp->nextp = cm_data.scacheHashTablep[hash];
!             cm_data.scacheHashTablep[hash] = scp;
              scp->flags |= CM_SCACHEFLAG_INHASH;
          }
          scp->refCount = 1;
***************
*** 1803,1810 ****
--- 1806,1817 ----
  #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,1820 ****
--- 1822,1842 ----
      osi_Log2(afsd_logp,"cm_ReleaseSCacheNoLock scp 0x%p ref %d",scp, refCount);
      afsi_log("%s:%d cm_ReleaseSCacheNoLock 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) {
+             if (lockstate != OSI_RWLOCK_WRITEHELD) 
+                 lock_ConvertRToW(&cm_scacheLock);
+             cm_RecycleSCache(scp, 0);
+             if (lockstate != OSI_RWLOCK_WRITEHELD) 
+                 lock_ConvertWToR(&cm_scacheLock);
+         }
+     }
  }
  
  #ifdef DEBUG_REFCOUNT
***************
*** 1837,1842 ****
--- 1859,1878 ----
      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);
  }
  
Index: openafs/src/WINNT/afsd/cm_scache.h
diff -c openafs/src/WINNT/afsd/cm_scache.h:1.21.2.24 openafs/src/WINNT/afsd/cm_scache.h:1.21.2.24.2.1
*** openafs/src/WINNT/afsd/cm_scache.h:1.21.2.24	Thu Mar 13 00:39:17 2008
--- openafs/src/WINNT/afsd/cm_scache.h	Sun Jun 22 23:05:03 2008
***************
*** 409,412 ****
--- 409,414 ----
  extern long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags);
  
  extern void cm_RemoveSCacheFromHashTable(cm_scache_t *scp);
+ 
+ extern void cm_AdjustScacheLRU(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.28 openafs/src/WINNT/afsd/cm_server.c:1.25.2.28.2.1
*** openafs/src/WINNT/afsd/cm_server.c:1.25.2.28	Thu Mar 13 00:39:17 2008
--- openafs/src/WINNT/afsd/cm_server.c	Sun Jun 22 22:54:28 2008
***************
*** 756,761 ****
--- 756,762 ----
      free(conntimer);
      free(deltas);
      free(results);
+     free(serversp);
      free(caps);
  }
  #endif /* MULTI_CHECKSERVERS */
Index: openafs/src/WINNT/afsd/cm_vnodeops.c
diff -c openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.74 openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.74.2.2
*** openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.74	Mon Apr 14 18:44:04 2008
--- openafs/src/WINNT/afsd/cm_vnodeops.c	Sun Jun 22 23:05:03 2008
***************
*** 1590,1595 ****
--- 1590,1596 ----
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
+     cm_scache_t *scp = NULL;
  
  #ifdef AFS_FREELANCE_CLIENT
      if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
***************
*** 1599,1604 ****
--- 1600,1607 ----
      }
  #endif  
  
+     code = cm_Lookup(dscp, namep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+ 
      /* make sure we don't screw up the dir status during the merge */
      code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
  
***************
*** 1661,1666 ****
--- 1664,1678 ----
      }
      cm_EndDirOp(&dirop);
  
+     if (scp) {
+         cm_ReleaseSCache(scp);
+         if (code == 0) {
+ 	    lock_ObtainWrite(&scp->rw);
+             scp->flags |= CM_SCACHEFLAG_DELETED;
+ 	    lock_ReleaseWrite(&scp->rw);
+         }
+     }
+ 
      return code;
  }
  
***************
*** 2974,2980 ****
          code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
              &newLinkStatus, &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
!         osi_Log1(smb_logp,"  RXAFS_Link returns 0x%x", code);
  
      } while (cm_Analyze(connp, userp, reqp,
          &dscp->fid, &volSync, NULL, NULL, code));
--- 2986,2992 ----
          code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
              &newLinkStatus, &updatedDirStatus, &volSync);
          rx_PutConnection(callp);
!         osi_Log1(afsd_logp,"  RXAFS_Link returns 0x%x", code);
  
      } while (cm_Analyze(connp, userp, reqp,
          &dscp->fid, &volSync, NULL, NULL, code));
***************
*** 3125,3130 ****
--- 3137,3145 ----
      AFSVolSync volSync;
      struct rx_connection * callp;
      cm_dirOp_t dirop;
+     cm_scache_t *scp = NULL;
+ 
+     code = cm_Lookup(dscp, namep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
  
      /* before starting the RPC, mark that we're changing the directory data,
       * so that someone who does a chmod on the dir will wait until our
***************
*** 3187,3192 ****
--- 3202,3216 ----
      }
      cm_EndDirOp(&dirop);
  
+     if (scp) {
+         cm_ReleaseSCache(scp);
+         if (code == 0) {
+ 	    lock_ObtainWrite(&scp->rw);
+             scp->flags |= CM_SCACHEFLAG_DELETED;
+ 	    lock_ReleaseWrite(&scp->rw);
+         }
+     }
+ 
      /* and return error code */
      return code;
  }
***************
*** 4973,4979 ****
                                   | CM_SCACHESYNC_LOCK);
  
                  if (code) {
!                     osi_Log1(smb_logp,
                               "cm_CheckLocks SyncOp failure code 0x%x", code);
                      goto post_syncopdone;
                  }
--- 4997,5003 ----
                                   | CM_SCACHESYNC_LOCK);
  
                  if (code) {
!                     osi_Log1(afsd_logp,
                               "cm_CheckLocks SyncOp failure code 0x%x", code);
                      goto post_syncopdone;
                  }
***************
*** 5299,5305 ****
  			 | CM_SCACHESYNC_GETSTATUS
  			 | CM_SCACHESYNC_LOCK);
          if (code) {
!             osi_Log1(smb_logp, "cm_RetryLock SyncOp failure code 0x%x", code);
              lock_ReleaseWrite(&cm_scacheLock);
              goto post_syncopdone;
          }
--- 5323,5329 ----
  			 | CM_SCACHESYNC_GETSTATUS
  			 | CM_SCACHESYNC_LOCK);
          if (code) {
!             osi_Log1(afsd_logp, "cm_RetryLock SyncOp failure code 0x%x", code);
              lock_ReleaseWrite(&cm_scacheLock);
              goto post_syncopdone;
          }
Index: openafs/src/WINNT/afsd/smb.c
diff -c openafs/src/WINNT/afsd/smb.c:1.118.2.70 openafs/src/WINNT/afsd/smb.c:1.118.2.70.2.1
*** openafs/src/WINNT/afsd/smb.c:1.118.2.70	Sun Mar  9 11:25:01 2008
--- openafs/src/WINNT/afsd/smb.c	Sun Jun 22 23:05:04 2008
***************
*** 6086,6092 ****
      char *pathp = NULL;
      cm_scache_t * scp = NULL;
      cm_scache_t *delscp = NULL;
-     int deleted = 0;
      int nullcreator = 0;
  
      osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
--- 6086,6091 ----
***************
*** 6205,6211 ****
          if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
              code = cm_RemoveDir(dscp, fullPathp, userp, &req);
  	    if (code == 0) {
- 		deleted = 1;
  		if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
  		    smb_NotifyChange(FILE_ACTION_REMOVED,
  				      FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
--- 6204,6209 ----
***************
*** 6214,6220 ****
          } else {
              code = cm_Unlink(dscp, fullPathp, userp, &req);
  	    if (code == 0) {				
- 		deleted = 1;
  		if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
  		    smb_NotifyChange(FILE_ACTION_REMOVED,
  				      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
--- 6212,6217 ----
***************
*** 6259,6270 ****
  	cm_ReleaseSCache(dscp);
  
      if (delscp) {
- 	if (deleted) {
- 	    lock_ObtainWrite(&delscp->rw);
- 	    if (deleted)
- 		delscp->flags |= CM_SCACHEFLAG_DELETED;
- 	    lock_ReleaseWrite(&delscp->rw);
- 	}
          cm_ReleaseSCache(delscp);
      }
  
--- 6256,6261 ----
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.30 openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.30.2.2
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.30	Mon Apr 21 11:44:06 2008
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm	Mon Jun 23 00:09:20 2008
***************
*** 57,63 ****
  
  <h1>OpenAFS for Windows</h1>
  
! <h2>Version 1.5.35</h2>
  
  <p class=MsoNormal>&nbsp; </p>
  
--- 57,63 ----
  
  <h1>OpenAFS for Windows</h1>
  
! <h2>Version 1.5.39</h2>
  
  <p class=MsoNormal>&nbsp; </p>
  
***************
*** 80,86 ****
  <span
  style='font-family:Symbol'>·<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  </span></span><a
! href="ReleaseNotes/relnotes-frames.htm">OpenAFS for Windows 1.5.35
  Release Notes</a></p>
  
  <p style='margin-left:36.0pt;text-indent:-18.0pt;'>
--- 80,86 ----
  <span
  style='font-family:Symbol'>·<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  </span></span><a
! href="ReleaseNotes/relnotes-frames.htm">OpenAFS for Windows 1.5.36
  Release Notes</a></p>
  
  <p style='margin-left:36.0pt;text-indent:-18.0pt;'>
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.30 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.30.2.2
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.30	Mon Apr 21 11:44:11 2008
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm	Mon Jun 23 00:09:20 2008
***************
*** 18,24 ****
  .shape {behavior:url(#default#VML);}
  </style>
  <![endif]-->
! <title>OpenAFS for Windows 1.5.35 Release Notes</title>
  <!--[if gte mso 9]><xml>
   <o:DocumentProperties>
    <o:Revision>1</o:Revision>
--- 18,24 ----
  .shape {behavior:url(#default#VML);}
  </style>
  <![endif]-->
! <title>OpenAFS for Windows 1.5.39 Release Notes</title>
  <!--[if gte mso 9]><xml>
   <o:DocumentProperties>
    <o:Revision>1</o:Revision>
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes-frames.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes-frames.htm:1.1.4.32 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes-frames.htm:1.1.4.32.2.2
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes-frames.htm:1.1.4.32	Mon Apr 21 11:44:11 2008
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes-frames.htm	Mon Jun 23 00:09:21 2008
***************
*** 9,15 ****
  <meta name=Generator content="Microsoft Word 12">
  <meta name=Originator content="Microsoft Word 12">
  <link rel=File-List href="relnotes-frames_files/filelist.xml">
! <title>OpenAFS for Windows 1.5.35 Release Notes</title>
  <link rel=themeData href="relnotes-frames_files/themedata.thmx">
  <link rel=colorSchemeMapping href="relnotes-frames_files/colorschememapping.xml">
  <!--[if gte mso 9]><xml>
--- 9,15 ----
  <meta name=Generator content="Microsoft Word 12">
  <meta name=Originator content="Microsoft Word 12">
  <link rel=File-List href="relnotes-frames_files/filelist.xml">
! <title>OpenAFS for Windows 1.5.39 Release Notes</title>
  <link rel=themeData href="relnotes-frames_files/themedata.thmx">
  <link rel=colorSchemeMapping href="relnotes-frames_files/colorschememapping.xml">
  <!--[if gte mso 9]><xml>
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes.htm:1.6.4.37 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes.htm:1.6.4.37.2.2
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes.htm:1.6.4.37	Mon Apr 21 11:44:11 2008
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/relnotes.htm	Mon Jun 23 00:09:21 2008
***************
*** 21,27 ****
  .shape {behavior:url(#default#VML);}
  </style>
  <![endif]-->
! <title>OpenAFS for Windows 1.5.35 Release Notes</title>
  <o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
   name="PostalCode"/>
  <o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
--- 21,27 ----
  .shape {behavior:url(#default#VML);}
  </style>
  <![endif]-->
! <title>OpenAFS for Windows 1.5.39 Release Notes</title>
  <o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
   name="PostalCode"/>
  <o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
***************
*** 1282,1288 ****
  
  <div class=Section1>
  
! <p class=MsoTitle>OpenAFS for Windows 1.5.35<br>
  Release Notes</p>
  
  <p class=MsoBodyText>The Andrew File System (AFS) is a location-independent
--- 1282,1288 ----
  
  <div class=Section1>
  
! <p class=MsoTitle>OpenAFS for Windows 1.5.39<br>
  Release Notes</p>
  
  <p class=MsoBodyText>The Andrew File System (AFS) is a location-independent
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm:1.2.6.31 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm:1.2.6.31.2.2
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm:1.2.6.31	Mon Apr 21 11:44:12 2008
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm	Mon Jun 23 00:09:22 2008
***************
*** 11,17 ****
  <meta name=Originator content="Microsoft Word 12">
  <base target=body>
  <link rel=File-List href="toc_files/filelist.xml">
! <title>OpenAFS for Windows 1.5.35 Table of Contents</title>
  <!--[if gte mso 9]><xml>
   <o:DocumentProperties>
    <o:Author>Jeffrey Altman</o:Author>
--- 11,17 ----
  <meta name=Originator content="Microsoft Word 12">
  <base target=body>
  <link rel=File-List href="toc_files/filelist.xml">
! <title>OpenAFS for Windows 1.5.39 Table of Contents</title>
  <!--[if gte mso 9]><xml>
   <o:DocumentProperties>
    <o:Author>Jeffrey Altman</o:Author>
Index: openafs/src/afs/afs_init.c
diff -c openafs/src/afs/afs_init.c:1.37.4.5.2.1 openafs/src/afs/afs_init.c:1.37.4.5.2.2
*** openafs/src/afs/afs_init.c:1.37.4.5.2.1	Fri May 23 10:25:34 2008
--- openafs/src/afs/afs_init.c	Thu Jun 12 13:24:51 2008
***************
*** 17,23 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_init.c,v 1.37.4.5.2.1 2008/05/23 14:25:34 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.5.2.2 2008/06/12 17:24:51 shadow Exp $");
  
  #include "afs/stds.h"
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
***************
*** 123,130 ****
       */
      if (aVolumes < 50)
  	aVolumes = 50;
!     else if (aVolumes > 3000)
! 	aVolumes = 3000;
  
      tv = (struct volume *)afs_osi_Alloc(aVolumes * sizeof(struct volume));
      for (i = 0; i < aVolumes - 1; i++)
--- 123,130 ----
       */
      if (aVolumes < 50)
  	aVolumes = 50;
!     else if (aVolumes > 32767)
! 	aVolumes = 32767;
  
      tv = (struct volume *)afs_osi_Alloc(aVolumes * sizeof(struct volume));
      for (i = 0; i < aVolumes - 1; i++)
Index: openafs/src/afs/LINUX/osi_groups.c
diff -c openafs/src/afs/LINUX/osi_groups.c:1.28.4.13 openafs/src/afs/LINUX/osi_groups.c:1.28.4.13.2.1
*** openafs/src/afs/LINUX/osi_groups.c:1.28.4.13	Sat Apr 19 17:55:51 2008
--- openafs/src/afs/LINUX/osi_groups.c	Sun Jun  8 23:39:31 2008
***************
*** 20,26 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_groups.c,v 1.28.4.13 2008/04/19 21:55:51 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 20,26 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_groups.c,v 1.28.4.13.2.1 2008/06/09 03:39:31 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 646,652 ****
--- 646,656 ----
  #  endif
  	    rcu_read_lock();
  # endif
+ #if defined(EXPORTED_FIND_TASK_BY_PID)
  	p = find_task_by_pid(1);
+ #else
+ 	p = find_task_by_vpid(1);
+ #endif
  	if (p && p->user->session_keyring)
  	    __key_type_keyring = p->user->session_keyring->type;
  # ifdef EXPORTED_TASKLIST_LOCK
Index: openafs/src/afs/LINUX/osi_pag_module.c
diff -c openafs/src/afs/LINUX/osi_pag_module.c:1.1.2.7 openafs/src/afs/LINUX/osi_pag_module.c:1.1.2.7.2.1
*** openafs/src/afs/LINUX/osi_pag_module.c:1.1.2.7	Tue Aug 21 17:28:45 2007
--- openafs/src/afs/LINUX/osi_pag_module.c	Thu Jun 12 16:08:46 2008
***************
*** 15,21 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_pag_module.c,v 1.1.2.7 2007/08/21 21:28:45 shadow Exp $");
  
  #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
  #include <linux/module.h> /* early to avoid printf->printk mapping */
--- 15,21 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_pag_module.c,v 1.1.2.7.2.1 2008/06/12 20:08:46 shadow Exp $");
  
  #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
  #include <linux/module.h> /* early to avoid printf->printk mapping */
***************
*** 75,80 ****
--- 75,83 ----
  init_module(void)
  #endif
  {
+ #if !defined(EXPORTED_PROC_ROOT_FS) && defined(AFS_LINUX24_ENV)
+     char path[64];
+ #endif
      int err;
  
      osi_Init();
***************
*** 83,89 ****
--- 86,97 ----
      if (err)
  	return err;
  #ifdef AFS_LINUX24_ENV
+ #if defined(EXPORTED_PROC_ROOT_FS)
      openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
+ #else
+     sprintf(path, "fs/%s", PROC_FSDIRNAME);
+     openafs_procfs = proc_mkdir(path, NULL);
+ #endif
      osi_ioctl_init();
  #endif
  
***************
*** 102,114 ****
--- 110,130 ----
  cleanup_module(void)
  #endif
  {
+ #if !defined(EXPORTED_PROC_ROOT_FS) && defined(AFS_LINUX24_ENV)
+     char path[64];
+ #endif
      osi_syscall_clean();
  
      osi_linux_free_afs_memory();
  
  #ifdef AFS_LINUX24_ENV
      osi_ioctl_clean();
+ #if defined(EXPORTED_PROC_ROOT_FS)
      remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
+ #else
+     sprintf(path, "fs/%s", PROC_FSDIRNAME);
+     remove_proc_entry(path, NULL);
+ #endif
  #endif
      return;
  }
Index: openafs/src/afs/LINUX/osi_proc.c
diff -c openafs/src/afs/LINUX/osi_proc.c:1.1.2.3 openafs/src/afs/LINUX/osi_proc.c:1.1.2.3.4.1
*** openafs/src/afs/LINUX/osi_proc.c:1.1.2.3	Thu Dec 28 17:36:33 2006
--- openafs/src/afs/LINUX/osi_proc.c	Sun Jun  8 23:39:31 2008
***************
*** 15,21 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_proc.c,v 1.1.2.3 2006/12/28 22:36:33 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_proc.c,v 1.1.2.3.4.1 2008/06/09 03:39:31 shadow Exp $");
  
  #include <linux/module.h> /* early to avoid printf->printk mapping */
  #include "afs/sysincludes.h"
***************
*** 317,325 ****
  osi_proc_init(void)
  {
      struct proc_dir_entry *entry;
! 
      openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
! 
  #ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
      entry = create_proc_entry("unixusers", 0, openafs_procfs);
      if (entry) {
--- 317,332 ----
  osi_proc_init(void)
  {
      struct proc_dir_entry *entry;
! #if !defined(EXPORTED_PROC_ROOT_FS)
!     char path[64];
! #endif
!     
! #if defined(EXPORTED_PROC_ROOT_FS)
      openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs);
! #else
!     sprintf(path, "fs/%s", PROC_FSDIRNAME);
!     openafs_procfs = proc_mkdir(path, NULL);
! #endif
  #ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
      entry = create_proc_entry("unixusers", 0, openafs_procfs);
      if (entry) {
***************
*** 338,346 ****
  void
  osi_proc_clean(void)
  {
      remove_proc_entry(PROC_CELLSERVDB_NAME, openafs_procfs);
  #ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
      remove_proc_entry("unixusers", openafs_procfs);
  #endif
-     remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
  }
--- 345,362 ----
  void
  osi_proc_clean(void)
  {
+ #if !defined(EXPORTED_PROC_ROOT_FS)
+     char path[64];
+ #endif
+ 
+ #if defined(EXPORTED_PROC_ROOT_FS)
+     remove_proc_entry(PROC_FSDIRNAME, proc_root_fs);
+ #else
+     sprintf(path, "fs/%s", PROC_FSDIRNAME);
+     remove_proc_entry(path, NULL);
+ #endif
      remove_proc_entry(PROC_CELLSERVDB_NAME, openafs_procfs);
  #ifdef HAVE_KERNEL_LINUX_SEQ_FILE_H
      remove_proc_entry("unixusers", openafs_procfs);
  #endif
  }
Index: openafs/src/afs/LINUX/osi_sysctl.c
diff -c openafs/src/afs/LINUX/osi_sysctl.c:1.9.2.5 openafs/src/afs/LINUX/osi_sysctl.c:1.9.2.5.2.1
*** openafs/src/afs/LINUX/osi_sysctl.c:1.9.2.5	Fri Nov 23 08:40:47 2007
--- openafs/src/afs/LINUX/osi_sysctl.c	Thu Jun 12 16:08:46 2008
***************
*** 1,7 ****
  /*
   * osi_sysctl.c: Linux sysctl interface to OpenAFS
   *
!  * $Id: osi_sysctl.c,v 1.9.2.5 2007/11/23 13:40:47 shadow Exp $
   *
   * Written Jan 30, 2002 by Kris Van Hees (Sine Nomine Associates)
   */
--- 1,7 ----
  /*
   * osi_sysctl.c: Linux sysctl interface to OpenAFS
   *
!  * $Id: osi_sysctl.c,v 1.9.2.5.2.1 2008/06/12 20:08:46 shadow Exp $
   *
   * Written Jan 30, 2002 by Kris Van Hees (Sine Nomine Associates)
   */
***************
*** 108,114 ****
--- 108,118 ----
  	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 7, 
+ #endif
  	.procname	= "afs_blocksUsed",
  	.data		= &afs_blocksUsed,
  	.maxlen		= sizeof(afs_int32), 
***************
*** 116,122 ****
--- 120,130 ----
  	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 8, 
+ #endif
  	.procname	= "afs_blocksUsed_0",
  	.data		= &afs_blocksUsed_0,
  	.maxlen		= sizeof(afs_int32),
***************
*** 124,130 ****
--- 132,142 ----
       	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 9, 
+ #endif
  	.procname	= "afs_blocksUsed_1",
  	.data		= &afs_blocksUsed_1, 
  	.maxlen		= sizeof(afs_int32),
***************
*** 132,138 ****
--- 144,154 ----
  	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 10, 
+ #endif
  	.procname	= "afs_blocksUsed_2",
  	.data		= &afs_blocksUsed_2, 
  	.maxlen		= sizeof(afs_int32), 
***************
*** 140,146 ****
--- 156,166 ----
  	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 11, 
+ #endif
  	.procname	= "afs_pct1",
  	.data		= &afs_pct1, 
  	.maxlen		= sizeof(afs_int32),
***************
*** 148,154 ****
--- 168,178 ----
  	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 12, 
+ #endif
  	.procname	= "afs_pct2",
  	.data		= &afs_pct2, 
  	.maxlen		= sizeof(afs_int32),
***************
*** 156,162 ****
--- 180,190 ----
       	.proc_handler   = &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 13,
+ #endif
  	.procname	= "afs_cacheBlocks",
  	.data		= &afs_cacheBlocks,
  	.maxlen		= sizeof(afs_int32),
***************
*** 164,170 ****
--- 192,202 ----
      	.proc_handler	= &proc_dointvec
      },
      {
+ #if defined(SYSCTL_TABLE_CHECKING)
+ 	.ctl_name 	= CTL_UNNUMBERED, 
+ #else
  	.ctl_name	= 14, 
+ #endif
  	.procname	= "md5inum",
  	.data		= &afs_new_inum, 
  	.maxlen		= sizeof(afs_int32),
Index: openafs/src/afs/VNOPS/afs_vnop_symlink.c
diff -c openafs/src/afs/VNOPS/afs_vnop_symlink.c:1.24.4.4.2.1 openafs/src/afs/VNOPS/afs_vnop_symlink.c:1.24.4.4.2.2
*** openafs/src/afs/VNOPS/afs_vnop_symlink.c:1.24.4.4.2.1	Fri May 23 10:25:35 2008
--- openafs/src/afs/VNOPS/afs_vnop_symlink.c	Sun Jun  8 23:30:45 2008
***************
*** 22,28 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_symlink.c,v 1.24.4.4.2.1 2008/05/23 14:25:35 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 22,28 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_symlink.c,v 1.24.4.4.2.2 2008/06/09 03:30:45 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 119,125 ****
      InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
      InStatus.ClientModTime = osi_Time();
      alen = strlen(atargetName);	/* we want it to include the null */
!     if (*atargetName == '#' || *atargetName == '%') {
  	InStatus.UnixModeBits = 0644;	/* mt pt: null from "." at end */
  	if (alen == 1)
  	    alen++;		/* Empty string */
--- 119,125 ----
      InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
      InStatus.ClientModTime = osi_Time();
      alen = strlen(atargetName);	/* we want it to include the null */
!     if ( (*atargetName == '#' || *atargetName == '%') && alen > 1 && atargetName[alen-1] == '.') {
  	InStatus.UnixModeBits = 0644;	/* mt pt: null from "." at end */
  	if (alen == 1)
  	    alen++;		/* Empty string */
Index: openafs/src/budb/server.c
diff -c openafs/src/budb/server.c:1.16.2.9 openafs/src/budb/server.c:1.16.2.9.2.1
*** openafs/src/budb/server.c:1.16.2.9	Wed Apr  2 15:51:55 2008
--- openafs/src/budb/server.c	Sun Jun 22 22:49:26 2008
***************
*** 11,17 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/budb/server.c,v 1.16.2.9 2008/04/02 19:51:55 shadow Exp $");
  
  #include <fcntl.h>
  #include <sys/stat.h>
--- 11,17 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/budb/server.c,v 1.16.2.9.2.1 2008/06/23 02:49:26 jaltman Exp $");
  
  #include <fcntl.h>
  #include <sys/stat.h>
***************
*** 661,667 ****
      static char timestamp[20];
  
      lt = localtime(&t);
!     strftime(timestamp, 20, "%m/%d/%Y %T", lt);
      return timestamp;
  }
  
--- 661,667 ----
      static char timestamp[20];
  
      lt = localtime(&t);
!     strftime(timestamp, 20, "%m/%d/%Y %H:%M:%S", lt);
      return timestamp;
  }
  
Index: openafs/src/cf/linux-test4.m4
diff -c openafs/src/cf/linux-test4.m4:1.29.2.41.2.1 openafs/src/cf/linux-test4.m4:1.29.2.41.2.2
*** openafs/src/cf/linux-test4.m4:1.29.2.41.2.1	Tue May 20 16:39:38 2008
--- openafs/src/cf/linux-test4.m4	Sun Jun  8 23:39:30 2008
***************
*** 1024,1026 ****
--- 1024,1053 ----
      AC_DEFINE([EXPORTED_RCU_READ_LOCK], 1, [define if rcu_read_lock() is usable])
    fi])
   
+ AC_DEFUN([LINUX_EXPORTS_FIND_TASK_BY_PID], [
+   AC_MSG_CHECKING([if find_task_by_pid is usable])
+   AC_CACHE_VAL([ac_cv_linux_exports_find_task_by_pid], [
+     AC_TRY_KBUILD(
+ [#include <linux/sched.h>],
+ [pid_t p;
+ find_task_by_pid(p);],
+       ac_cv_linux_exports_find_task_by_pid=yes,
+       ac_cv_linux_exports_find_task_by_pid=no)])
+   AC_MSG_RESULT($ac_cv_linux_exports_find_task_by_pid)
+   if test "x$ac_cv_linux_exports_find_task_by_pid" = "xyes"; then
+     AC_DEFINE([EXPORTED_FIND_TASK_BY_PID], 1, [define if find_task_by_pid() is usable])
+   fi])
+  
+ AC_DEFUN([LINUX_EXPORTS_PROC_ROOT_FS], [
+   AC_MSG_CHECKING([if proc_root_fs is defined and exported])
+   AC_CACHE_VAL([ac_cv_linux_exports_proc_root_fs], [
+     AC_TRY_KBUILD(
+ [#include <linux/proc_fs.h>],
+ [struct proc_dir_entry *p = proc_root_fs;],
+       ac_cv_linux_exports_proc_root_fs=yes,
+       ac_cv_linux_exports_proc_root_fs=no)])
+   AC_MSG_RESULT($ac_cv_linux_exports_proc_root_fs)
+   if test "x$ac_cv_linux_exports_proc_root_fs" = "xyes"; then
+     AC_DEFINE([EXPORTED_PROC_ROOT_FS], 1, [define if proc_root_fs is exported])
+   fi])
+  
Index: openafs/src/config/NTMakefile.amd64_w2k
diff -c openafs/src/config/NTMakefile.amd64_w2k:1.24.2.41.2.2 openafs/src/config/NTMakefile.amd64_w2k:1.24.2.41.2.3
*** openafs/src/config/NTMakefile.amd64_w2k:1.24.2.41.2.2	Fri May 23 10:27:32 2008
--- openafs/src/config/NTMakefile.amd64_w2k	Mon Jun 23 00:13:15 2008
***************
*** 84,90 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3800
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
--- 84,90 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3900
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
Index: openafs/src/config/NTMakefile.i386_nt40
diff -c openafs/src/config/NTMakefile.i386_nt40:1.84.2.40.2.2 openafs/src/config/NTMakefile.i386_nt40:1.84.2.40.2.3
*** openafs/src/config/NTMakefile.i386_nt40:1.84.2.40.2.2	Fri May 23 10:27:32 2008
--- openafs/src/config/NTMakefile.i386_nt40	Mon Jun 23 00:13:15 2008
***************
*** 84,90 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3800
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
--- 84,90 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3900
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
Index: openafs/src/config/NTMakefile.i386_w2k
diff -c openafs/src/config/NTMakefile.i386_w2k:1.23.2.41.2.2 openafs/src/config/NTMakefile.i386_w2k:1.23.2.41.2.3
*** openafs/src/config/NTMakefile.i386_w2k:1.23.2.41.2.2	Fri May 23 10:27:32 2008
--- openafs/src/config/NTMakefile.i386_w2k	Mon Jun 23 00:13:15 2008
***************
*** 84,90 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3800
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
--- 84,90 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3900
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
Index: openafs/src/config/afsconfig-windows.h
diff -c openafs/src/config/afsconfig-windows.h:1.4 openafs/src/config/afsconfig-windows.h:1.4.20.1
*** openafs/src/config/afsconfig-windows.h:1.4	Fri Mar 11 00:38:26 2005
--- openafs/src/config/afsconfig-windows.h	Sun Jun 22 22:47:00 2008
***************
*** 168,173 ****
--- 168,179 ----
  /* Define if you have the <winsock2.h> header file.  */
  #define HAVE_WINSOCK2_H
  
+ /* Define if you have vsnprintf */
+ #define HAVE_VSNPRINTF 1
+ 
+ /* Define if you have snprintf */
+ #define HAVE_SNPRINTF 1
+ 
  /* Name of package */
  #undef PACKAGE
  
Index: openafs/src/packaging/Debian/.cvsignore
diff -c /dev/null openafs/src/packaging/Debian/.cvsignore:1.1.4.2
*** /dev/null	Tue Jun 24 09:08:46 2008
--- openafs/src/packaging/Debian/.cvsignore	Thu Jun 12 16:02:00 2008
***************
*** 0 ****
--- 1 ----
+ rules
Index: openafs/src/packaging/MacOS/.cvsignore
diff -c /dev/null openafs/src/packaging/MacOS/.cvsignore:1.1.4.2
*** /dev/null	Tue Jun 24 09:08:47 2008
--- openafs/src/packaging/MacOS/.cvsignore	Thu Jun 12 16:02:01 2008
***************
*** 0 ****
--- 1,3 ----
+ OpenAFS.Info.plist
+ OpenAFS.info
+ buildpkg.sh
Index: openafs/src/ptserver/display.c
diff -c openafs/src/ptserver/display.c:1.9.14.1 openafs/src/ptserver/display.c:1.9.14.1.2.1
*** openafs/src/ptserver/display.c:1.9.14.1	Tue Oct 30 11:16:43 2007
--- openafs/src/ptserver/display.c	Sun Jun 22 22:49:26 2008
***************
*** 11,17 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/display.c,v 1.9.14.1 2007/10/30 15:16:43 shadow Exp $");
  
  #include <afs/stds.h>
  #include <sys/types.h>
--- 11,17 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/display.c,v 1.9.14.1.2.1 2008/06/23 02:49:26 jaltman Exp $");
  
  #include <afs/stds.h>
  #include <sys/types.h>
***************
*** 46,54 ****
      }
      tm = localtime(&clock);
      if (tm->tm_year != this_year)
! 	strftime(buffer, 32, "%m/%d/%Y %T", tm);
      else
! 	strftime(buffer, 32, "%m/%d %T", tm);
      return buffer;
  }
  #endif
--- 46,54 ----
      }
      tm = localtime(&clock);
      if (tm->tm_year != this_year)
! 	strftime(buffer, 32, "%m/%d/%Y %H:%M:%S", tm);
      else
! 	strftime(buffer, 32, "%m/%d %H:%M:%S", tm);
      return buffer;
  }
  #endif
Index: openafs/src/ptserver/pt_util.c
diff -c openafs/src/ptserver/pt_util.c:1.11.4.4 openafs/src/ptserver/pt_util.c:1.11.4.4.2.1
*** openafs/src/ptserver/pt_util.c:1.11.4.4	Thu Mar 27 14:40:12 2008
--- openafs/src/ptserver/pt_util.c	Thu Jun 12 14:37:08 2008
***************
*** 1,4 ****
! /* $Id: pt_util.c,v 1.11.4.4 2008/03/27 18:40:12 shadow Exp $ */
  
  /*
   *
--- 1,4 ----
! /* $Id: pt_util.c,v 1.11.4.4.2.1 2008/06/12 18:37:08 shadow Exp $ */
  
  /*
   *
***************
*** 23,29 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/pt_util.c,v 1.11.4.4 2008/03/27 18:40:12 shadow Exp $");
  
  #include <afs/cmd.h>		/*Command line parsing */
  #include <errno.h>
--- 23,29 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/pt_util.c,v 1.11.4.4.2.1 2008/06/12 18:37:08 shadow Exp $");
  
  #include <afs/cmd.h>		/*Command line parsing */
  #include <errno.h>
***************
*** 321,328 ****
      } else {
  	for (i = 0; i < HASHSIZE; i++) {
  	    upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
! 	    while (upos)
! 		upos = display_entry(upos);
  	}
  	if (flags & DO_GRP)
  	    display_groups();
--- 321,336 ----
      } else {
  	for (i = 0; i < HASHSIZE; i++) {
  	    upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]);
! 	    while (upos) {
! 		long newpos;
! 		newpos = display_entry(upos);
! 		if (newpos == upos) {
! 		    fprintf(stderr, "pt_util: hash error in %s chain %d\n", 
! 			    nflag ? "name":"id", i);
! 		    exit(1);
! 		} else
! 		    upos = newpos;
! 	    }
  	}
  	if (flags & DO_GRP)
  	    display_groups();
Index: openafs/src/ptserver/utils.c
diff -c openafs/src/ptserver/utils.c:1.15.14.3 openafs/src/ptserver/utils.c:1.15.14.3.2.1
*** openafs/src/ptserver/utils.c:1.15.14.3	Wed Apr  2 15:51:56 2008
--- openafs/src/ptserver/utils.c	Thu Jun 12 14:37:08 2008
***************
*** 7,17 ****
   * directory or online at http://www.openafs.org/dl/license10.html
   */
  
  #include <afsconfig.h>
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/utils.c,v 1.15.14.3 2008/04/02 19:51:56 shadow Exp $");
  
  #include <sys/types.h>
  #include <lock.h>
--- 7,18 ----
   * directory or online at http://www.openafs.org/dl/license10.html
   */
  
+ #include <assert.h>
  #include <afsconfig.h>
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ptserver/utils.c,v 1.15.14.3.2.1 2008/06/12 18:37:08 shadow Exp $");
  
  #include <sys/types.h>
  #include <lock.h>
***************
*** 294,299 ****
--- 295,301 ----
  	return 0;
      if (aid == tentry.id)
  	return entry;
+     assert(entry != tentry.nextID);
      entry = tentry.nextID;
      while (entry != 0) {
  	memset(&tentry, 0, sizeof(tentry));
***************
*** 302,307 ****
--- 304,310 ----
  	    return 0;
  	if (aid == tentry.id)
  	    return entry;
+ 	assert(entry != tentry.nextID);
  	entry = tentry.nextID;
      }
      return 0;
***************
*** 325,330 ****
--- 328,334 ----
  	return 0;
      if ((strncmp(aname, tentryp->name, PR_MAXNAMELEN)) == 0)
  	return entry;
+     assert(entry != tentryp->nextName);
      entry = tentryp->nextName;
      while (entry != 0) {
  	memset(tentryp, 0, sizeof(struct prentry));
***************
*** 333,338 ****
--- 337,343 ----
  	    return 0;
  	if ((strncmp(aname, tentryp->name, PR_MAXNAMELEN)) == 0)
  	    return entry;
+ 	assert(entry != tentryp->nextName);
  	entry = tentryp->nextName;
      }
      return 0;
***************
*** 462,467 ****
--- 467,473 ----
      if (code)
  	return PRDBFAIL;
      while (aid != tentry.id) {
+ 	assert(trail != current);
  	trail = current;
  	current = tentry.nextID;
  	if (current == 0)
***************
*** 539,544 ****
--- 545,551 ----
      if (code)
  	return PRDBFAIL;
      while (strcmp(aname, tentry.name)) {
+ 	assert(trail != current);
  	trail = current;
  	current = tentry.nextName;
  	if (current == 0)
Index: openafs/src/rx/rx.c
diff -c openafs/src/rx/rx.c:1.97.2.20.2.5 openafs/src/rx/rx.c:1.97.2.20.2.6
*** openafs/src/rx/rx.c:1.97.2.20.2.5	Fri May 23 10:56:02 2008
--- openafs/src/rx/rx.c	Sun Jun 22 23:20:50 2008
***************
*** 17,23 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx.c,v 1.97.2.20.2.5 2008/05/23 14:56:02 shadow Exp $");
  
  #ifdef KERNEL
  #include "afs/sysincludes.h"
--- 17,23 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx.c,v 1.97.2.20.2.6 2008/06/23 03:20:50 jaltman Exp $");
  
  #ifdef KERNEL
  #include "afs/sysincludes.h"
***************
*** 358,364 ****
   * by the kernel.  Whether this will ever overlap anything in
   * /etc/services is anybody's guess...  Returns 0 on success, -1 on
   * error. */
! static int rxinit_status = 1;
  #ifdef AFS_PTHREAD_ENV
  /*
   * This mutex protects the following global variables:
--- 358,367 ----
   * by the kernel.  Whether this will ever overlap anything in
   * /etc/services is anybody's guess...  Returns 0 on success, -1 on
   * error. */
! #ifndef AFS_NT40_ENV
! static
! #endif
! int rxinit_status = 1;
  #ifdef AFS_PTHREAD_ENV
  /*
   * This mutex protects the following global variables:
Index: openafs/src/rx/rx_user.c
diff -c openafs/src/rx/rx_user.c:1.24.4.2.2.1 openafs/src/rx/rx_user.c:1.24.4.2.2.2
*** openafs/src/rx/rx_user.c:1.24.4.2.2.1	Tue May 20 17:59:43 2008
--- openafs/src/rx/rx_user.c	Sun Jun 22 23:20:50 2008
***************
*** 13,19 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_user.c,v 1.24.4.2.2.1 2008/05/20 21:59:43 shadow Exp $");
  
  # include <sys/types.h>
  # include <errno.h>
--- 13,19 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_user.c,v 1.24.4.2.2.2 2008/06/23 03:20:50 jaltman Exp $");
  
  # include <sys/types.h>
  # include <errno.h>
***************
*** 325,339 ****
  #endif
  
  #ifdef AFS_NT40_ENV
  void
  rx_GetIFInfo(void)
  {
      u_int maxsize;
      u_int rxsize;
-     int npackets, ncbufs;
      afs_uint32 i;
  
      LOCK_IF_INIT;
      Inited = 1;
      UNLOCK_IF_INIT;
  
--- 325,360 ----
  #endif
  
  #ifdef AFS_NT40_ENV
+ extern int rxinit_status;
+ void 
+ rxi_InitMorePackets(void) {
+     int npackets, ncbufs;
+ 
+     ncbufs = (rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE);
+     if (ncbufs > 0) {
+         ncbufs = ncbufs / RX_CBUFFERSIZE;
+         npackets = rx_initSendWindow - 1;
+         rxi_MorePackets(npackets * (ncbufs + 1));
+     }
+ }
  void
  rx_GetIFInfo(void)
  {
      u_int maxsize;
      u_int rxsize;
      afs_uint32 i;
  
      LOCK_IF_INIT;
+     if (Inited) {
+         if (Inited < 2 && rxinit_status == 0) {
+             /* We couldn't initialize more packets earlier.
+              * Do it now. */
+             rxi_InitMorePackets();
+             Inited = 2;
+         }
+         UNLOCK_IF_INIT;
+ 	return;
+     }
      Inited = 1;
      UNLOCK_IF_INIT;
  
***************
*** 355,366 ****
  
      }
      UNLOCK_IF;
!     ncbufs = (rx_maxJumboRecvSize - RX_FIRSTBUFFERSIZE);
!     if (ncbufs > 0) {
!         ncbufs = ncbufs / RX_CBUFFERSIZE;
!         npackets = rx_initSendWindow - 1;
!         rxi_MorePackets(npackets * (ncbufs + 1));
!     }
  }
  #endif
  
--- 376,391 ----
  
      }
      UNLOCK_IF;
! 
!     /*
!      * If rxinit_status is still set, rx_InitHost() has yet to be called
!      * and we therefore do not have any mutex locks initialized.  As a
!      * result we cannot call rxi_MorePackets() without crashing.
!      */
!     if (rxinit_status)
!         return;
! 
!     rxi_InitMorePackets();
  }
  #endif
  
Index: openafs/src/tbudb/.cvsignore
diff -c /dev/null openafs/src/tbudb/.cvsignore:1.1.4.2
*** /dev/null	Tue Jun 24 09:08:52 2008
--- openafs/src/tbudb/.cvsignore	Thu Jun 12 16:01:55 2008
***************
*** 0 ****
--- 1 ----
+ Makefile
Index: openafs/src/tptserver/.cvsignore
diff -c /dev/null openafs/src/tptserver/.cvsignore:1.1.4.2
*** /dev/null	Tue Jun 24 09:08:53 2008
--- openafs/src/tptserver/.cvsignore	Thu Jun 12 16:01:59 2008
***************
*** 0 ****
--- 1 ----
+ Makefile
Index: openafs/src/tubik/.cvsignore
diff -c /dev/null openafs/src/tubik/.cvsignore:1.1.4.2
*** /dev/null	Tue Jun 24 09:08:53 2008
--- openafs/src/tubik/.cvsignore	Thu Jun 12 16:01:59 2008
***************
*** 0 ****
--- 1 ----
+ Makefile
Index: openafs/src/tubik/Makefile.in
diff -c openafs/src/tubik/Makefile.in:1.1.2.5 openafs/src/tubik/Makefile.in:1.1.2.5.2.2
*** openafs/src/tubik/Makefile.in:1.1.2.5	Fri Apr  4 10:52:03 2008
--- openafs/src/tubik/Makefile.in	Tue Jun 24 08:59:17 2008
***************
*** 24,30 ****
  RXOBJS = rx_pthread.o
  
  UTILOBJS=assert.o uuid.o serverLog.o fileutil.o netutils.o dirpath.o \
!      volparse.o flipbase64.o softsig.o hostparse.o snprintf.o pthread_glock.o
  
  LIBS=${RXOBJS} ${UTILOBJS} ${TOP_LIBDIR}/libafsrpc.a ${TOP_LIBDIR}/liblwp.a \
       ${TOP_LIBDIR}/libcom_err.a ${TOP_LIBDIR}/libcmd.a \
--- 24,31 ----
  RXOBJS = rx_pthread.o
  
  UTILOBJS=assert.o uuid.o serverLog.o fileutil.o netutils.o dirpath.o \
!        volparse.o flipbase64.o softsig.o hostparse.o snprintf.o \
!        pthread_glock.o strlcat.o strlcpy.o strnlen.o
  
  LIBS=${RXOBJS} ${UTILOBJS} ${TOP_LIBDIR}/libafsrpc.a ${TOP_LIBDIR}/liblwp.a \
       ${TOP_LIBDIR}/libcom_err.a ${TOP_LIBDIR}/libcmd.a \
***************
*** 66,71 ****
--- 67,81 ----
  volparse.o: ${UTIL}/volparse.c
  	${CCRULE}
  
+ strlcat.o: ${UTIL}/strlcat.c
+ 	${CCRULE}
+ 
+ strlcpy.o: ${UTIL}/strlcpy.c
+ 	${CCRULE}
+ 
+ strnlen.o: ${UTIL}/strnlen.c
+ 	${CCRULE}
+ 
  flipbase64.o: ${UTIL}/flipbase64.c
  	${CCRULE}
  
Index: openafs/src/tvlserver/.cvsignore
diff -c /dev/null openafs/src/tvlserver/.cvsignore:1.1.4.2
*** /dev/null	Tue Jun 24 09:08:53 2008
--- openafs/src/tvlserver/.cvsignore	Thu Jun 12 16:02:00 2008
***************
*** 0 ****
--- 1 ----
+ Makefile
Index: openafs/src/ubik/udebug.c
diff -c openafs/src/ubik/udebug.c:1.18.4.3 openafs/src/ubik/udebug.c:1.18.4.3.2.1
*** openafs/src/ubik/udebug.c:1.18.4.3	Mon Apr 28 11:20:41 2008
--- openafs/src/ubik/udebug.c	Sun May 25 09:50:50 2008
***************
*** 11,17 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ubik/udebug.c,v 1.18.4.3 2008/04/28 15:20:41 jaltman Exp $");
  
  #include <sys/types.h>
  #include <stdlib.h>
--- 11,17 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/ubik/udebug.c,v 1.18.4.3.2.1 2008/05/25 13:50:50 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdlib.h>
***************
*** 192,198 ****
      } else {
  	diff = udebug.now - udebug.lastYesTime;
  	printf("Last yes vote for %s was %d secs ago (%ssync site); \n",
! 	       afs_inet_ntoa(htonl(udebug.lastYesHost)), (int)diff,
  	       ((udebug.lastYesState) ? "" : "not "));
  
  	diff = udebug.now - udebug.lastYesClaim;
--- 192,198 ----
      } else {
  	diff = udebug.now - udebug.lastYesTime;
  	printf("Last yes vote for %s was %d secs ago (%ssync site); \n",
! 	       afs_inet_ntoa(udebug.lastYesHost), (int)diff,
  	       ((udebug.lastYesState) ? "" : "not "));
  
  	diff = udebug.now - udebug.lastYesClaim;
Index: openafs/src/util/volparse.c
diff -c openafs/src/util/volparse.c:1.11.14.1 openafs/src/util/volparse.c:1.11.14.1.2.1
*** openafs/src/util/volparse.c:1.11.14.1	Tue Oct 30 11:16:48 2007
--- openafs/src/util/volparse.c	Thu Jun 12 15:23:49 2008
***************
*** 11,24 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/volparse.c,v 1.11.14.1 2007/10/30 15:16:48 shadow Exp $");
  
  #include <string.h>
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  
! /* map a partition id from any partition-style name */
  afs_int32
  volutil_GetPartitionID(char *aname)
  {
--- 11,35 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/util/volparse.c,v 1.11.14.1.2.1 2008/06/12 19:23:49 shadow Exp $");
  
  #include <string.h>
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  
! /**
!  * map a partition id from any partition-style name.
!  *
!  * @param[in] aname  partition name string
!  *
!  * @return partition index number
!  *   @retval -1  invalid partition name
!  *
!  * @see volutil_PartitionName2_r
!  * @see volutil_PartitionName_r
!  * @see volutil_PartitionName
!  */
  afs_int32
  volutil_GetPartitionID(char *aname)
  {
***************
*** 69,108 ****
      }
  }
  
! /* map a partition number back into a partition string */
! #define BAD_VID "BAD VOLUME ID"
! #define BAD_VID_LEN (sizeof(BAD_VID))
! char *
! volutil_PartitionName_r(int avalue, char *tbuffer, int buflen)
  {
      char tempString[3];
      register int i;
  
!     if (buflen < BAD_VID_LEN) {
! 	if (buflen > 3)
! 	    (void)strcpy(tbuffer, "SPC");
! 	else
! 	    tbuffer[0] = '\0';
! 	return tbuffer;
      }
!     memset(tbuffer, 0, buflen);
      tempString[1] = tempString[2] = 0;
!     strcpy(tbuffer, "/vicep");
!     if (avalue < 0 || avalue >= (26 * 26 + 26)) {
! 	strcpy(tbuffer, "BAD VOLUME ID");
!     } else if (avalue <= 25) {
! 	tempString[0] = 'a' + avalue;
! 	strcat(tbuffer, tempString);
      } else {
! 	avalue -= 26;
! 	i = (avalue / 26);
  	tempString[0] = i + 'a';
! 	tempString[1] = (avalue % 26) + 'a';
! 	strcat(tbuffer, tempString);
      }
      return tbuffer;
  }
  
  char *
  volutil_PartitionName(int avalue)
  {
--- 80,181 ----
      }
  }
  
! /**
!  * convert a partition index number into a partition name string (/vicepXX).
!  *
!  * @param[in]  part     partition index number
!  * @param[out] tbuffer  buffer in which to store name
!  * @param[in]  buflen   length of tbuffer
!  *
!  * @return operation status
!  *   @retval 0   success
!  *   @retval -1  buffer too short
!  *   @retval -2  invalid partition id
!  *
!  * @see volutil_PartitionName_r
!  * @see volutil_PartitionName
!  * @see volutil_GetPartitionID
!  */
! afs_int32
! volutil_PartitionName2_r(afs_int32 part, char *tbuffer, size_t buflen)
  {
      char tempString[3];
      register int i;
  
!     if (part < 0 || part >= (26 * 26 + 26)) {
! 	return -2;
      }
! 
      tempString[1] = tempString[2] = 0;
!     strncpy(tbuffer, "/vicep", buflen);
!     if (part <= 25) {
! 	tempString[0] = 'a' + part;
      } else {
! 	part -= 26;
! 	i = (part / 26);
  	tempString[0] = i + 'a';
! 	tempString[1] = (part % 26) + 'a';
!     }
!     if (strlcat(tbuffer, tempString, buflen) >= buflen) {
! 	return -1;
!     }
!     return tbuffer;
! }
! 
! #define BAD_VID "BAD VOLUME ID"
! #define BAD_VID_LEN (sizeof(BAD_VID))
! /**
!  * convert a partition index number into a partition name string (/vicepXX).
!  *
!  * @param[in]  part     partition index number
!  * @param[out] tbuffer  buffer in which to store name
!  * @param[in]  buflen   length of tbuffer
!  *
!  * @return partition name string
!  *   @retval ""               buffer too short
!  *   @retval "SPC"            buffer too short
!  *   @retval "BAD VOLUME ID"  avalue contains an invalid partition index
!  *
!  * @note you may wish to consider using volutil_PartitionName2_r, as its
!  *       error handling is more standard
!  *
!  * @see volutil_PartitionName2_r
!  * @see volutil_PartitionName
!  * @see volutil_GetPartitionID
!  */
! char *
! volutil_PartitionName_r(int part, char *tbuffer, int buflen)
! {
!     afs_int32 code;
! 
!     if (buflen < BAD_VID_LEN) {
! 	strlcpy(tbuffer, "SPC", buflen);
! 	return tbuffer;
!     }
! 
!     code = volutil_PartitionName2_r(part, tbuffer, buflen);
! 
!     if (code == -2) {
! 	strlcpy(tbuffer, BAD_VID, buflen);
      }
+ 
      return tbuffer;
  }
  
+ /**
+  * convert a partition index number into a partition name string (/vicepXX).
+  *
+  * @param[in] avalue  partition index number
+  *
+  * @return partition name string
+  *   @retval "BAD VOLUME ID"  avalue contains an invalid partition index
+  *
+  * @warning this interface is not re-entrant
+  *
+  * @see volutil_PartitionName2_r
+  * @see volutil_PartitionName_r
+  * @see volutil_GetPartitionID
+  */
  char *
  volutil_PartitionName(int avalue)
  {
Index: openafs/src/vol/daemon_com.c
diff -c openafs/src/vol/daemon_com.c:1.3.4.7 openafs/src/vol/daemon_com.c:1.3.4.7.2.1
*** openafs/src/vol/daemon_com.c:1.3.4.7	Tue Apr  1 16:05:36 2008
--- openafs/src/vol/daemon_com.c	Thu Jun 12 15:23:52 2008
***************
*** 22,28 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/daemon_com.c,v 1.3.4.7 2008/04/01 20:05:36 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdio.h>
--- 22,28 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/daemon_com.c,v 1.3.4.7.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdio.h>
***************
*** 369,375 ****
--- 369,394 ----
  	goto done;
      }
  
+     /*
+      * fill in some common header fields
+      */
      com->hdr.proto_version = state->proto_version;
+     com->hdr.pkt_seq = ++state->pkt_seq;
+     com->hdr.com_seq = ++state->com_seq;
+ #ifdef AFS_NT40_ENV
+     com->hdr.pid = 0;
+     com->hdr.tid = 0;
+ #else
+     com->hdr.pid = getpid();
+ #ifdef AFS_PTHREAD_ENV
+     com->hdr.tid = (afs_int32)pthread_self();
+ #else
+     {
+ 	PROCESS handle = LWP_ThreadId();
+ 	com->hdr.tid = (handle) ? handle->index : 0;
+     }
+ #endif /* !AFS_PTHREAD_ENV */
+ #endif /* !AFS_NT40_ENV */
  
      memcpy(buf, &com->hdr, sizeof(com->hdr));
      if (com->payload.len) {
***************
*** 473,487 ****
  /**
   * receive a command structure off a sync socket.
   *
!  * @param[in] fd    socket descriptor
!  * @param[out] com  sync command object to be populated
   *
   * @return operation status
   *    @retval SYNC_OK command received
   *    @retval SYNC_COM_ERROR there was a socket communications error
   */
  afs_int32
! SYNC_getCom(int fd, SYNC_command * com)
  {
      int n;
      afs_int32 code = SYNC_OK;
--- 492,509 ----
  /**
   * receive a command structure off a sync socket.
   *
!  * @param[in]  state  pointer to server-side state object
!  * @param[in]  fd     file descriptor on which to perform i/o
!  * @param[out] com    sync command object to be populated
   *
   * @return operation status
   *    @retval SYNC_OK command received
   *    @retval SYNC_COM_ERROR there was a socket communications error
   */
  afs_int32
! SYNC_getCom(SYNC_server_state_t * state,
! 	    int fd,
! 	    SYNC_command * com)
  {
      int n;
      afs_int32 code = SYNC_OK;
***************
*** 546,560 ****
  /**
   * write a response structure to a sync socket.
   *
!  * @param[in] fd
!  * @param[in] res
   *
   * @return operation status
   *    @retval SYNC_OK
   *    @retval SYNC_COM_ERROR
   */
  afs_int32
! SYNC_putRes(int fd, SYNC_response * res)
  {
      int n;
      afs_int32 code = SYNC_OK;
--- 568,585 ----
  /**
   * write a response structure to a sync socket.
   *
!  * @param[in] state  handle to server-side state object
!  * @param[in] fd     file descriptor on which to perform i/o
!  * @param[in] res    handle to response packet
   *
   * @return operation status
   *    @retval SYNC_OK
   *    @retval SYNC_COM_ERROR
   */
  afs_int32
! SYNC_putRes(SYNC_server_state_t * state, 
! 	    int fd,
! 	    SYNC_response * res)
  {
      int n;
      afs_int32 code = SYNC_OK;
***************
*** 575,580 ****
--- 600,608 ----
  #ifdef AFS_DEMAND_ATTACH_FS
      res->hdr.flags |= SYNC_FLAG_DAFS_EXTENSIONS;
  #endif
+     res->hdr.proto_version = state->proto_version;
+     res->hdr.pkt_seq = ++state->pkt_seq;
+     res->hdr.res_seq = ++state->res_seq;
  
      memcpy(buf, &res->hdr, sizeof(res->hdr));
      if (res->payload.len) {
Index: openafs/src/vol/daemon_com.h
diff -c openafs/src/vol/daemon_com.h:1.1.4.3 openafs/src/vol/daemon_com.h:1.1.4.3.2.1
*** openafs/src/vol/daemon_com.h:1.1.4.3	Fri Mar 14 00:42:52 2008
--- openafs/src/vol/daemon_com.h	Thu Jun 12 15:23:52 2008
***************
*** 8,14 ****
   */
  
  #ifndef _AFS_VOL_DAEMON_COM_H
! #define _AFS_VOL_DAEMON_COM_H
  
  /* 
   * SYNC protocol constants
--- 8,14 ----
   */
  
  #ifndef _AFS_VOL_DAEMON_COM_H
! #define _AFS_VOL_DAEMON_COM_H 1
  
  /* 
   * SYNC protocol constants
***************
*** 48,54 ****
      SYNC_COM_ERROR            = 2,  /**< sync protocol communicaions error */
      SYNC_BAD_COMMAND          = 3,  /**< sync command code not implemented by server */
      SYNC_FAILED               = 4,  /**< sync server-side procedure failed */
!     SYNC_REASON_CODE_END
  };
  
  /* SYNC protocol reason codes
--- 48,54 ----
      SYNC_COM_ERROR            = 2,  /**< sync protocol communicaions error */
      SYNC_BAD_COMMAND          = 3,  /**< sync command code not implemented by server */
      SYNC_FAILED               = 4,  /**< sync server-side procedure failed */
!     SYNC_RESPONSE_CODE_END
  };
  
  /* SYNC protocol reason codes
***************
*** 61,69 ****
  
  /* general reason codes */
  #define SYNC_REASON_NONE                 0
! #define SYNC_REASON_MALFORMED_PACKET     1
! #define SYNC_REASON_NOMEM                2
  #define SYNC_REASON_ENCODING_ERROR       3
  
  /* SYNC protocol flags
   *
--- 61,70 ----
  
  /* general reason codes */
  #define SYNC_REASON_NONE                 0
! #define SYNC_REASON_MALFORMED_PACKET     1   /**< command packet was malformed */
! #define SYNC_REASON_NOMEM                2   /**< sync server out of memory */
  #define SYNC_REASON_ENCODING_ERROR       3
+ #define SYNC_REASON_PAYLOAD_TOO_BIG      4   /**< payload too big for response packet buffer */
  
  /* SYNC protocol flags
   *
***************
*** 120,125 ****
--- 121,128 ----
      int listen_depth;           /**< socket listen queue depth */
      char * proto_name;          /**< sync protocol associated with this conn */
      SYNC_sockaddr_t addr;       /**< server listen socket sockaddr */
+     afs_uint32 pkt_seq;         /**< packet xmit sequence counter */
+     afs_uint32 res_seq;         /**< response xmit sequence counter */
  } SYNC_server_state_t;
  
  /**
***************
*** 132,156 ****
      int retry_limit;            /**< max number of times for SYNC_ask to retry */
      afs_int32 hard_timeout;     /**< upper limit on time to keep trying */
      char * proto_name;          /**< sync protocol associated with this conn */
!     byte fatal_error;           /**< nonzer if fatal error on this client conn */
  } SYNC_client_state;
  
  /* wire types */
  typedef struct SYNC_command_hdr {
!     afs_uint32 proto_version;   /* sync protocol version */
!     afs_int32 programType;      /* type of program issuing the request */
!     afs_int32 command;          /* request type */
!     afs_int32 reason;           /* reason for request */
!     afs_uint32 command_len;     /* entire length of command */
!     afs_uint32 flags;
  } SYNC_command_hdr;
  
  typedef struct SYNC_response_hdr {
!     afs_uint32 proto_version;    /* sync protocol version */
!     afs_uint32 response_len;    /* entire length of response */
!     afs_int32 response;         /* response code */
!     afs_int32 reason;           /* reason for response */
!     afs_uint32 flags;
  } SYNC_response_hdr;
  
  
--- 135,174 ----
      int retry_limit;            /**< max number of times for SYNC_ask to retry */
      afs_int32 hard_timeout;     /**< upper limit on time to keep trying */
      char * proto_name;          /**< sync protocol associated with this conn */
!     byte fatal_error;           /**< nonzero if fatal error on this client conn */
!     afs_uint32 pkt_seq;         /**< packet xmit sequence counter */
!     afs_uint32 com_seq;         /**< command xmit sequence counter */
  } SYNC_client_state;
  
  /* wire types */
+ /**
+  * on-wire command packet header.
+  */
  typedef struct SYNC_command_hdr {
!     afs_uint32 proto_version;   /**< sync protocol version */
!     afs_uint32 pkt_seq;         /**< packet sequence number */
!     afs_uint32 com_seq;         /**< command sequence number */
!     afs_int32 programType;      /**< type of program issuing the request */
!     afs_int32 pid;              /**< pid of requestor */
!     afs_int32 tid;              /**< thread id of requestor */
!     afs_int32 command;          /**< request type */
!     afs_int32 reason;           /**< reason for request */
!     afs_uint32 command_len;     /**< entire length of command */
!     afs_uint32 flags;           /**< miscellanous control flags */
  } SYNC_command_hdr;
  
+ /**
+  * on-wire response packet header.
+  */
  typedef struct SYNC_response_hdr {
!     afs_uint32 proto_version;   /**< sync protocol version */
!     afs_uint32 pkt_seq;         /**< packet sequence number */
!     afs_uint32 com_seq;         /**< in response to com_seq... */
!     afs_uint32 res_seq;         /**< response sequence number */
!     afs_uint32 response_len;    /**< entire length of response */
!     afs_int32 response;         /**< response code */
!     afs_int32 reason;           /**< reason for response */
!     afs_uint32 flags;           /**< miscellanous control flags */
  } SYNC_response_hdr;
  
  
***************
*** 185,192 ****
  extern int SYNC_reconnect(SYNC_client_state *);           /* do a reconnect after a protocol error, or from a forked child */
  
  /* server-side prototypes */
! extern int SYNC_getCom(int fd, SYNC_command * com);
! extern int SYNC_putRes(int fd, SYNC_response * res);
  extern int SYNC_verifyProtocolString(char * buf, size_t len);
  extern void SYNC_cleanupSock(SYNC_server_state_t * state);
  extern int SYNC_bindSock(SYNC_server_state_t * state);
--- 203,210 ----
  extern int SYNC_reconnect(SYNC_client_state *);           /* do a reconnect after a protocol error, or from a forked child */
  
  /* server-side prototypes */
! extern int SYNC_getCom(SYNC_server_state_t *, int fd, SYNC_command * com);
! extern int SYNC_putRes(SYNC_server_state_t *, int fd, SYNC_response * res);
  extern int SYNC_verifyProtocolString(char * buf, size_t len);
  extern void SYNC_cleanupSock(SYNC_server_state_t * state);
  extern int SYNC_bindSock(SYNC_server_state_t * state);
Index: openafs/src/vol/fssync-debug.c
diff -c openafs/src/vol/fssync-debug.c:1.1.4.4 openafs/src/vol/fssync-debug.c:1.1.4.4.2.1
*** openafs/src/vol/fssync-debug.c:1.1.4.4	Mon Mar 17 12:05:28 2008
--- openafs/src/vol/fssync-debug.c	Thu Jun 12 15:23:52 2008
***************
*** 19,25 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/fssync-debug.c,v 1.1.4.4 2008/03/17 16:05:28 shadow Exp $");
  
  #include <stdlib.h>
  #include <stdio.h>
--- 19,25 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/fssync-debug.c,v 1.1.4.4.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <stdlib.h>
  #include <stdio.h>
***************
*** 98,103 ****
--- 98,106 ----
  static int VolBreakCBKs(struct cmd_syndesc * as, void * rock);
  static int VolMove(struct cmd_syndesc * as, void * rock);
  static int VolList(struct cmd_syndesc * as, void * rock);
+ static int VolLeaveOff(struct cmd_syndesc * as, void * rock);
+ static int VolForceAttach(struct cmd_syndesc * as, void * rock);
+ static int VolForceError(struct cmd_syndesc * as, void * rock);
  static int VolQuery(struct cmd_syndesc * as, void * rock);
  static int VolHdrQuery(struct cmd_syndesc * as, void * rock);
  static int VolOpQuery(struct cmd_syndesc * as, void * rock);
***************
*** 180,185 ****
--- 183,197 ----
      VOLOP_PARMS_DECL(ts);
      cmd_CreateAlias(ts, "ls");
  
+     ts = cmd_CreateSyntax("leaveoff", VolLeaveOff, 0, "leave volume offline (FSYNC_VOL_LEAVE_OFF opcode)");
+     VOLOP_PARMS_DECL(ts);
+ 
+     ts = cmd_CreateSyntax("attach", VolForceAttach, 0, "force full attachment (FSYNC_VOL_ATTACH opcode)");
+     VOLOP_PARMS_DECL(ts);
+ 
+     ts = cmd_CreateSyntax("error", VolForceError, 0, "force into hard error state (FSYNC_VOL_FORCE_ERROR opcode)");
+     VOLOP_PARMS_DECL(ts);
+ 
      ts = cmd_CreateSyntax("query", VolQuery, NULL, "get volume structure (FSYNC_VOL_QUERY opcode)");
      VOLOP_PARMS_DECL(ts);
      cmd_CreateAlias(ts, "qry");
***************
*** 500,505 ****
--- 512,556 ----
      return 0;
  }
  
+ static int
+ VolLeaveOff(struct cmd_syndesc * as, void * rock)
+ {
+     struct state state;
+ 
+     common_prolog(as, &state);
+     common_volop_prolog(as, &state);
+ 
+     do_volop(&state, FSYNC_VOL_LEAVE_OFF, NULL);
+ 
+     return 0;
+ }
+ 
+ static int
+ VolForceAttach(struct cmd_syndesc * as, void * rock)
+ {
+     struct state state;
+ 
+     common_prolog(as, &state);
+     common_volop_prolog(as, &state);
+ 
+     do_volop(&state, FSYNC_VOL_ATTACH, NULL);
+ 
+     return 0;
+ }
+ 
+ static int
+ VolForceError(struct cmd_syndesc * as, void * rock)
+ {
+     struct state state;
+ 
+     common_prolog(as, &state);
+     common_volop_prolog(as, &state);
+ 
+     do_volop(&state, FSYNC_VOL_FORCE_ERROR, NULL);
+ 
+     return 0;
+ }
+ 
  #ifdef AFS_DEMAND_ATTACH_FS
  static char *
  vol_state_to_string(VolState state)
***************
*** 835,842 ****
--- 886,897 ----
  
  	printf("\tcom = {\n");
  	printf("\t\tproto_version  = %u\n", vop.com.proto_version);
+ 	printf("\t\tpkt_seq        = %u\n", vop.com.pkt_seq);
+ 	printf("\t\tcom_seq        = %u\n", vop.com.com_seq);
  	printf("\t\tprogramType    = %d (%s)\n", 
  	       vop.com.programType, program_type_to_string(vop.com.programType));
+ 	printf("\t\tpid            = %d\n", vop.com.pid);
+ 	printf("\t\ttid            = %d\n", vop.com.tid);
  	printf("\t\tcommand        = %d (%s)\n", 
  	       vop.com.command, command_code_to_string(vop.com.command));
  	printf("\t\treason         = %d (%s)\n", 
Index: openafs/src/vol/fssync-server.c
diff -c openafs/src/vol/fssync-server.c:1.1.4.10 openafs/src/vol/fssync-server.c:1.1.4.10.2.1
*** openafs/src/vol/fssync-server.c:1.1.4.10	Tue Apr  1 16:05:36 2008
--- openafs/src/vol/fssync-server.c	Thu Jun 12 15:23:52 2008
***************
*** 53,59 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/fssync-server.c,v 1.1.4.10 2008/04/01 20:05:36 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdio.h>
--- 53,59 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/fssync-server.c,v 1.1.4.10.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdio.h>
***************
*** 179,184 ****
--- 179,186 ----
  
  static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
  
+ static int FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon);
+ 
  
  /*
   * This lock controls access to the handler array. The overhead
***************
*** 230,235 ****
--- 232,240 ----
      int tid;
  #endif
      SYNC_server_state_t * state = &fssync_server_state;
+ #ifdef AFS_DEMAND_ATTACH_FS
+     VThreadOptions_t * thread_opts;
+ #endif
  
      SYNC_getAddr(&state->endpoint, &state->addr);
      SYNC_cleanupSock(state);
***************
*** 256,266 ****
  	LWP_DispatchProcess();
  #endif /* AFS_PTHREAD_ENV */
      }
- 
      state->fd = SYNC_getSock(&state->endpoint);
      code = SYNC_bindSock(state);
      assert(!code);
  
      InitHandler();
      AcceptOn();
  
--- 261,286 ----
  	LWP_DispatchProcess();
  #endif /* AFS_PTHREAD_ENV */
      }
      state->fd = SYNC_getSock(&state->endpoint);
      code = SYNC_bindSock(state);
      assert(!code);
  
+ #ifdef AFS_DEMAND_ATTACH_FS
+     /*
+      * make sure the volume package is incapable of recursively executing
+      * salvsync calls on this thread, since there is a possibility of
+      * deadlock.
+      */
+     thread_opts = malloc(sizeof(VThreadOptions_t));
+     if (thread_opts == NULL) {
+ 	Log("failed to allocate memory for thread-specific volume package options structure\n");
+ 	return NULL;
+     }
+     memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
+     thread_opts->disallow_salvsync = 1;
+     assert(pthread_setspecific(VThread_key, thread_opts) == 0);
+ #endif
+ 
      InitHandler();
      AcceptOn();
  
***************
*** 321,332 ****
      com.payload.buf = (void *)com_buf;
      com.payload.len = SYNC_PROTO_MAX_LEN;
      res.hdr.response_len = sizeof(res.hdr);
-     res.hdr.proto_version = FSYNC_PROTO_VERSION;
      res.payload.len = SYNC_PROTO_MAX_LEN;
      res.payload.buf = (void *)res_buf;
  
      FS_cnt++;
!     if (SYNC_getCom(fd, &com)) {
  	Log("FSYNC_com:  read failed; dropping connection (cnt=%d)\n", FS_cnt);
  	FSYNC_Drop(fd);
  	return;
--- 341,351 ----
      com.payload.buf = (void *)com_buf;
      com.payload.len = SYNC_PROTO_MAX_LEN;
      res.hdr.response_len = sizeof(res.hdr);
      res.payload.len = SYNC_PROTO_MAX_LEN;
      res.payload.buf = (void *)res_buf;
  
      FS_cnt++;
!     if (SYNC_getCom(&fssync_server_state, fd, &com)) {
  	Log("FSYNC_com:  read failed; dropping connection (cnt=%d)\n", FS_cnt);
  	FSYNC_Drop(fd);
  	return;
***************
*** 353,358 ****
--- 372,378 ----
  	goto respond;
      }
  
+     res.hdr.com_seq = com.hdr.com_seq;
  
      VOL_LOCK;
      switch (com.hdr.command) {
***************
*** 388,394 ****
      VOL_UNLOCK;
  
   respond:
!     SYNC_putRes(fd, &res);
      if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
  	FSYNC_Drop(fd);
      }
--- 408,414 ----
      VOL_UNLOCK;
  
   respond:
!     SYNC_putRes(&fssync_server_state, fd, &res);
      if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
  	FSYNC_Drop(fd);
      }
***************
*** 464,469 ****
--- 484,513 ----
      return code;
  }
  
+ /**
+  * service an FSYNC request to bring a volume online.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK volume transitioned online
+  *   @retval SYNC_FAILED invalid command protocol message
+  *   @retval SYNC_DENIED operation could not be completed
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_ON
+  *       - FSYNC_VOL_ATTACH
+  *       - FSYNC_VOL_LEAVE_OFF
+  *
+  * @note the supplementary reason code contains additional details.
+  *       When SYNC_DENIED is returned, the specific reason is
+  *       placed in the response packet reason field.
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
***************
*** 478,526 ****
  	goto done;
      }
  
-     /*
-       This is where a detatched volume gets reattached. However in the
-       special case where the volume is merely busy, it is already
-       attatched and it is only necessary to clear the busy flag. See
-       defect #2080 for details.
-     */
- 
-     /* is the volume already attatched? */
- #ifdef	notdef
-     /*
-      * XXX With the following enabled we had bizarre problems where the backup id would
-      * be reset to 0; that was due to the interaction between fileserver/volserver in that they
-      * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
-      * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
-      * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
-      * be done right XXX
-      */
-     vp = VGetVolume_r(&error, vcom->vop->volume);
-     if (vp) {
- 	/* yep, is the BUSY flag set? */
- 	if (vp->specialStatus == VBUSY) {
- 
- 	    /* yep, clear BUSY flag */
- 
- 	    vp->specialStatus = 0;
- 	    /* make sure vol is online */
- 	    if (vcom->v) {
- 		vcom->v->volumeID = 0;
- 		V_inUse(vp) = 1;	/* online */
- 	    }
- 	    VPutVolume_r(vp);
- 	    break;
- 	}
- 	VPutVolume_r(vp);
-     }
- #endif /* notdef */
- 
      /* so, we need to attach the volume */
  
  #ifdef AFS_DEMAND_ATTACH_FS
      /* check DAFS permissions */
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
!     if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName) &&
  	vp->pending_vol_op && 
  	(vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
  	/* a different program has this volume checked out. deny. */
--- 522,534 ----
  	goto done;
      }
  
      /* so, we need to attach the volume */
  
  #ifdef AFS_DEMAND_ATTACH_FS
      /* check DAFS permissions */
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
!     if (vp &&
! 	FSYNC_partMatch(vcom, vp, 1) &&
  	vp->pending_vol_op && 
  	(vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
  	/* a different program has this volume checked out. deny. */
***************
*** 545,554 ****
      if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
  	/* nothing much to do if we're leaving the volume offline */
  #ifdef AFS_DEMAND_ATTACH_FS
! 	if (vp &&
! 	    !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
! 	    VDeregisterVolOp_r(vp);
! 	    VChangeState_r(vp, VOL_STATE_UNATTACHED);
  	}
  #endif
  	goto done;
--- 553,575 ----
      if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
  	/* nothing much to do if we're leaving the volume offline */
  #ifdef AFS_DEMAND_ATTACH_FS
! 	if (vp) {
! 	    if (FSYNC_partMatch(vcom, vp, 1)) {
! 		if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
! 		    (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
! 		    VChangeState_r(vp, VOL_STATE_UNATTACHED);
! 		    VDeregisterVolOp_r(vp);
! 		} else {
! 		    code = SYNC_DENIED;
! 		    res->hdr.reason = FSYNC_BAD_STATE;
! 		}
! 	    } else {
! 		code = SYNC_DENIED;
! 		res->hdr.reason = FSYNC_WRONG_PART;
! 	    }
! 	} else {
! 	    code = SYNC_DENIED;
! 	    res->hdr.reason = FSYNC_UNKNOWN_VOLID;
  	}
  #endif
  	goto done;
***************
*** 581,586 ****
--- 602,630 ----
      return code;
  }
  
+ /**
+  * service an FSYNC request to take a volume offline.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK volume transitioned offline
+  *   @retval SYNC_FAILED invalid command protocol message
+  *   @retval SYNC_DENIED operation could not be completed
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_OFF 
+  *       - FSYNC_VOL_NEEDVOLUME
+  *
+  * @note the supplementary reason code contains additional details.
+  *       When SYNC_DENIED is returned, the specific reason is
+  *       placed in the response packet reason field.
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
***************
*** 589,594 ****
--- 633,641 ----
      int i;
      Volume * vp, * nvp;
      Error error;
+ #ifdef AFS_DEMAND_ATTACH_FS
+     int reserved = 0;
+ #endif
  
      if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
  	res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
***************
*** 623,631 ****
  #endif
  
      if (vp) {
! 	if ((vcom->vop->partName[0] != 0) &&
! 	    (strncmp(vcom->vop->partName, vp->partition->name, 
! 		    sizeof(vcom->vop->partName)) != 0)) {
  	    /* volume on desired partition is not online, so we
  	     * should treat this as an offline volume.
  	     */
--- 670,676 ----
  #endif
  
      if (vp) {
! 	    if (!FSYNC_partMatch(vcom, vp, 1)) {
  	    /* volume on desired partition is not online, so we
  	     * should treat this as an offline volume.
  	     */
***************
*** 683,697 ****
  	 */
  	switch (type) {
  	case salvageServer:
  	case debugUtility:
- 	    /* give the salvageserver lots of liberty */
  	    break;
  	case volumeUtility:
! 	    if ((V_attachState(vp) == VOL_STATE_ERROR) ||
! 		(V_attachState(vp) == VOL_STATE_SALVAGING)) {
  		goto deny;
  	    }
  	    break;
  	default:
  	    Log("bad program type passed to FSSYNC\n");
  	    goto deny;
--- 728,748 ----
  	 */
  	switch (type) {
  	case salvageServer:
+ 	    /* it is possible for the salvageserver to checkout a 
+ 	     * volume for salvage before its scheduling request
+ 	     * has been sent to the salvageserver */
+ 	    if (vp->salvage.requested && !vp->salvage.scheduled) {
+ 		vp->salvage.scheduled = 1;
+ 	    }
  	case debugUtility:
  	    break;
+ 
  	case volumeUtility:
! 	    if (VIsErrorState(V_attachState(vp))) {
  		goto deny;
  	    }
  	    break;
+ 
  	default:
  	    Log("bad program type passed to FSSYNC\n");
  	    goto deny;
***************
*** 718,733 ****
  	/* convert to heavyweight ref */
  	nvp = VGetVolumeByVp_r(&error, vp);
  
- 	/* register the volume operation metadata with the volume */
- 	VRegisterVolOp_r(vp, &info);
- 
  	if (!nvp) {
  	    Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
  		vcom->vop->volume);
  	    res->hdr.reason = FSYNC_VOL_PKG_ERROR;
  	    goto deny;
  	}
! 	vp = nvp;
      }
  #endif /* AFS_DEMAND_ATTACH_FS */
  
--- 769,788 ----
  	/* convert to heavyweight ref */
  	nvp = VGetVolumeByVp_r(&error, vp);
  
  	if (!nvp) {
  	    Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
  		vcom->vop->volume);
  	    res->hdr.reason = FSYNC_VOL_PKG_ERROR;
  	    goto deny;
+ 	} else if (nvp != vp) {
+ 	    /* i don't think this should ever happen, but just in case... */
+ 	    Log("FSYNC_com_VolOff: warning: potentially dangerous race detected\n");
+ 	    vp = nvp;
  	}
! 
! 	/* register the volume operation metadata with the volume */
! 	VRegisterVolOp_r(vp, &info);
! 
      }
  #endif /* AFS_DEMAND_ATTACH_FS */
  
***************
*** 769,780 ****
--- 824,867 ----
      return SYNC_DENIED;
  }
  
+ /**
+  * service an FSYNC request to mark a volume as moved.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK volume marked as moved to a remote server
+  *   @retval SYNC_FAILED invalid command protocol message
+  *   @retval SYNC_DENIED current volume state does not permit this operation
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this operation also breaks all callbacks for the given volume
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_MOVE
+  *
+  * @note the supplementary reason code contains additional details.  For
+  *       instance, SYNC_OK is still returned when the partition specified
+  *       does not match the one registered in the volume object -- reason
+  *       will be FSYNC_WRONG_PART in this case.
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
+     afs_int32 code = SYNC_DENIED;
      Error error;
      Volume * vp;
  
+     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+ 	res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+ 	code = SYNC_FAILED;
+ 	goto done;
+     }
+ 
      /* Yuch:  the "reason" for the move is the site it got moved to... */
      /* still set specialStatus so we stop sending back VBUSY.
       * also should still break callbacks.  Note that I don't know
***************
*** 787,799 ****
      vp = VGetVolume_r(&error, vcom->vop->volume);
  #endif
      if (vp) {
! 	vp->specialStatus = VMOVED;
! #ifndef AFS_DEMAND_ATTACH_FS
! 	VPutVolume_r(vp);
  #endif
      }
  
!     if (V_BreakVolumeCallbacks) {
  	Log("fssync: volume %u moved to %x; breaking all call backs\n",
  	    vcom->vop->volume, vcom->hdr->reason);
  	VOL_UNLOCK;
--- 874,900 ----
      vp = VGetVolume_r(&error, vcom->vop->volume);
  #endif
      if (vp) {
! 	if (FSYNC_partMatch(vcom, vp, 1)) {
! #ifdef AFS_DEMAND_ATTACH_FS
! 	    if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
! 		(V_attachState(vp) == VOL_STATE_PREATTACHED)) {
! #endif
! 		code = SYNC_OK;
! 		vp->specialStatus = VMOVED;
! #ifdef AFS_DEMAND_ATTACH_FS
! 	    } else {
! 		res->hdr.reason = FSYNC_BAD_STATE;
! 	    }
  #endif
+ 	} else {
+ 	    res->hdr.reason = FSYNC_WRONG_PART;
+ 	}
+ 	VPutVolume_r(vp);
+     } else {
+ 	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
      }
  
!     if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
  	Log("fssync: volume %u moved to %x; breaking all call backs\n",
  	    vcom->vop->volume, vcom->hdr->reason);
  	VOL_UNLOCK;
***************
*** 801,817 ****
  	VOL_LOCK;
      }
  
!     return SYNC_OK;
  }
  
  static afs_int32
  FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
  #ifdef AFS_DEMAND_ATTACH_FS
      Error error;
      Volume * vp;
  #endif
  
      /* don't try to put online, this call is made only after deleting
       * a volume, in which case we want to remove the vol # from the
       * OfflineVolumes array only */
--- 902,949 ----
  	VOL_LOCK;
      }
  
! 
!  done:
!     return code;
  }
  
+ /**
+  * service an FSYNC request to mark a volume as destroyed.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK volume marked as destroyed
+  *   @retval SYNC_FAILED invalid command protocol message
+  *   @retval SYNC_DENIED current volume state does not permit this operation
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_DONE
+  *
+  * @note the supplementary reason code contains additional details.  For
+  *       instance, SYNC_OK is still returned when the partition specified
+  *       does not match the one registered in the volume object -- reason
+  *       will be FSYNC_WRONG_PART in this case.
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
+     afs_int32 code = SYNC_FAILED;
  #ifdef AFS_DEMAND_ATTACH_FS
      Error error;
      Volume * vp;
  #endif
  
+     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+ 	res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+ 	goto done;
+     }
+ 
      /* don't try to put online, this call is made only after deleting
       * a volume, in which case we want to remove the vol # from the
       * OfflineVolumes array only */
***************
*** 821,858 ****
  #ifdef AFS_DEMAND_ATTACH_FS
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
      if (vp) {
! 	VChangeState_r(vp, VOL_STATE_UNATTACHED);
! 	VDeregisterVolOp_r(vp);
      }
  #endif
  
!     return SYNC_OK;
  }
  
  #ifdef AFS_DEMAND_ATTACH_FS
  /**
!  * force a volume into the hard error state.
   */
  static afs_int32
  FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
      Error error;
      Volume * vp;
!     afs_int32 code = SYNC_DENIED;
  
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
!     if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
! 	memset(&vp->salvage, 0, sizeof(vp->salvage));
! 	VChangeState_r(vp, VOL_STATE_ERROR);
! 	code = SYNC_OK;
      } else {
  	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
      }
! 	
      return code;
  }
! #endif
  
  static afs_int32
  FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
--- 953,1059 ----
  #ifdef AFS_DEMAND_ATTACH_FS
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
      if (vp) {
! 	if (FSYNC_partMatch(vcom, vp, 1)) {
! 	    if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
! 		(V_attachState(vp) == VOL_STATE_PREATTACHED)) {
! 		VChangeState_r(vp, VOL_STATE_UNATTACHED);
! 		VDeregisterVolOp_r(vp);
! 		code = SYNC_OK;
! 	    } else {
! 		code = SYNC_DENIED;
! 		res->hdr.reason = FSYNC_BAD_STATE;
! 	    }
! 	} else {
! 	    code = SYNC_OK; /* XXX is this really a good idea? */
! 	    res->hdr.reason = FSYNC_WRONG_PART;
! 	}
!     } else {
! 	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
      }
  #endif
  
!  done:
!     return code;
  }
  
  #ifdef AFS_DEMAND_ATTACH_FS
  /**
!  * service an FSYNC request to transition a volume to the hard error state.
!  *
!  * @param[in]   vcom  pointer command object
!  * @param[out]  res   object in which to store response packet
!  *
!  * @return operation status
!  *   @retval SYNC_OK volume transitioned to hard error state
!  *   @retval SYNC_FAILED invalid command protocol message
!  *   @retval SYNC_DENIED (see note)
!  *
!  * @note this is an FSYNC RPC server stub
!  *
!  * @note this procedure handles the following FSSYNC command codes:
!  *       - FSYNC_VOL_FORCE_ERROR
!  *
!  * @note SYNC_DENIED is returned in the following cases:
!  *        - no partition name is specified (reason field set to
!  *          FSYNC_WRONG_PART).
!  *        - volume id not known to fileserver (reason field set
!  *          to FSYNC_UNKNOWN_VOLID).
!  *
!  * @note demand attach fileserver only
!  *
!  * @internal
   */
  static afs_int32
  FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
      Error error;
      Volume * vp;
!     afs_int32 code = SYNC_FAILED;
! 
!     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
! 	res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
! 	goto done;
!     }
  
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
!     if (vp) {
! 	if (FSYNC_partMatch(vcom, vp, 0)) {
! 	    /* null out salvsync control state, as it's no longer relevant */
! 	    memset(&vp->salvage, 0, sizeof(vp->salvage));
! 	    VChangeState_r(vp, VOL_STATE_ERROR);
! 	    code = SYNC_OK;
! 	} else {
! 	    res->hdr.reason = FSYNC_WRONG_PART;
! 	}
      } else {
  	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
      }
! 
!  done:
      return code;
  }
! #endif /* AFS_DEMAND_ATTACH_FS */
  
+ /**
+  * service an FSYNC request to break all callbacks for this volume.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK callback breaks scheduled for volume
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_BREAKCBKS
+  *
+  * @note demand attach fileserver only
+  *
+  * @todo should do partition matching
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
***************
*** 867,879 ****
      return SYNC_OK;
  }
  
  static afs_int32
  FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
!     afs_int32 code = SYNC_OK;
      Error error;
      Volume * vp;
  
  #ifdef AFS_DEMAND_ATTACH_FS
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
  #else /* !AFS_DEMAND_ATTACH_FS */
--- 1068,1102 ----
      return SYNC_OK;
  }
  
+ /**
+  * service an FSYNC request to return the Volume object.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK      volume object returned to caller
+  *   @retval SYNC_FAILED  bad command packet, or failed to locate volume object
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_QUERY
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
!     afs_int32 code = SYNC_FAILED;
      Error error;
      Volume * vp;
  
+     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+ 	res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+ 	goto done;
+     }
+ 
  #ifdef AFS_DEMAND_ATTACH_FS
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
  #else /* !AFS_DEMAND_ATTACH_FS */
***************
*** 881,938 ****
  #endif /* !AFS_DEMAND_ATTACH_FS */
  
      if (vp) {
! 	assert(sizeof(Volume) <= res->payload.len);
! 	memcpy(res->payload.buf, vp, sizeof(Volume));
! 	res->hdr.response_len += sizeof(Volume);
  #ifndef AFS_DEMAND_ATTACH_FS
  	VPutVolume_r(vp);
  #endif
      } else {
  	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
- 	code = SYNC_FAILED;
      }
      return code;
  }
  
  static afs_int32
  FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
!     afs_int32 code = SYNC_OK;
      Error error;
      Volume * vp;
      int hdr_ok = 0;
  
  #ifdef AFS_DEMAND_ATTACH_FS
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
-     if (vp &&
- 	(vp->header != NULL) &&
- 	(V_attachFlags(vp) & VOL_HDR_ATTACHED) &&
- 	(V_attachFlags(vp) & VOL_HDR_LOADED)) {
- 	hdr_ok = 1;
-     }
  #else /* !AFS_DEMAND_ATTACH_FS */
      vp = VGetVolume_r(&error, vcom->vop->volume);
!     if (vp && vp->header) {
! 	hdr_ok = 1;
!     }
  #endif /* !AFS_DEMAND_ATTACH_FS */
  
   load_done:
!     if (hdr_ok) {
! 	assert(sizeof(VolumeDiskData) <= res->payload.len);
! 	memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
! 	res->hdr.response_len += sizeof(VolumeDiskData);
  #ifndef AFS_DEMAND_ATTACH_FS
! 	VPutVolume_r(vp);
  #endif
!     } else {
! 	if (vp) {
! 	    res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
! 	} else {
! 	    res->hdr.reason = FSYNC_UNKNOWN_VOLID;
! 	}
! 	code = SYNC_FAILED;
!     }
      return code;
  }
  
--- 1104,1204 ----
  #endif /* !AFS_DEMAND_ATTACH_FS */
  
      if (vp) {
! 	if (FSYNC_partMatch(vcom, vp, 1)) {
! 	    if (res->payload.len >= sizeof(Volume)) {
! 		memcpy(res->payload.buf, vp, sizeof(Volume));
! 		res->hdr.response_len += sizeof(Volume);
! 		code = SYNC_OK;
! 	    } else {
! 		res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
! 	    }
! 	} else {
! 	    res->hdr.reason = FSYNC_WRONG_PART;
! 	}
  #ifndef AFS_DEMAND_ATTACH_FS
  	VPutVolume_r(vp);
  #endif
      } else {
  	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
      }
+ 
+  done:
      return code;
  }
  
+ /**
+  * service an FSYNC request to return the Volume header.
+  *
+  * @param[in]   vcom  pointer command object
+  * @param[out]  res   object in which to store response packet
+  *
+  * @return operation status
+  *   @retval SYNC_OK volume header returned to caller
+  *   @retval SYNC_FAILED  bad command packet, or failed to locate volume header
+  *
+  * @note this is an FSYNC RPC server stub
+  *
+  * @note this procedure handles the following FSSYNC command codes:
+  *       - FSYNC_VOL_QUERY_HDR
+  *
+  * @internal
+  */
  static afs_int32
  FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
  {
!     afs_int32 code = SYNC_FAILED;
      Error error;
      Volume * vp;
      int hdr_ok = 0;
  
+     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
+ 	res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+ 	goto done;
+     }
+     if (res->payload.len < sizeof(VolumeDiskData)) {
+ 	res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
+ 	goto done;
+     }
+ 
  #ifdef AFS_DEMAND_ATTACH_FS
      vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
  #else /* !AFS_DEMAND_ATTACH_FS */
      vp = VGetVolume_r(&error, vcom->vop->volume);
! #endif
! 
!     if (vp) {
! 	if (FSYNC_partMatch(vcom, vp, 1)) {
! #ifdef AFS_DEMAND_ATTACH_FS
! 	    if ((vp->header == NULL) ||
! 		!(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
! 		!(V_attachFlags(vp) & VOL_HDR_LOADED)) {
! 		res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
! 		goto done;
! 	    }
! #else /* !AFS_DEMAND_ATTACH_FS */
! 	    if (!vp || !vp->header) {
! 		res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
! 		goto done;
! 	    }
  #endif /* !AFS_DEMAND_ATTACH_FS */
+ 	} else {
+ 	    res->hdr.reason = FSYNC_WRONG_PART;
+ 	    goto done;
+ 	}
+     } else {
+ 	res->hdr.reason = FSYNC_UNKNOWN_VOLID;
+ 	goto done;
+     }
  
   load_done:
!     memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
!     res->hdr.response_len += sizeof(VolumeDiskData);
  #ifndef AFS_DEMAND_ATTACH_FS
!     VPutVolume_r(vp);
  #endif
!     code = SYNC_OK;
! 
!  done:
      return code;
  }
  
***************
*** 1148,1153 ****
--- 1414,1430 ----
  }
  #endif /* AFS_DEMAND_ATTACH_FS */
  
+ /**
+  * populate an FSSYNC_VolOp_info object from a command packet object.
+  *
+  * @param[in]   vcom  pointer to command packet
+  * @param[out]  info  pointer to info object which will be populated
+  *
+  * @note FSSYNC_VolOp_info objects are attached to Volume objects when
+  *       a volume operation is commenced.
+  *
+  * @internal
+  */
  static void
  FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
  {
***************
*** 1155,1160 ****
--- 1432,1464 ----
      memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
  }
  
+ /**
+  * check whether command packet partition name matches volume 
+  * object's partition name.
+  *
+  * @param[in] vcom        pointer to command packet
+  * @param[in] vp          pointer to volume object
+  * @param[in] match_anon  anon matching control flag (see note below)
+  *
+  * @return whether partitions match
+  *   @retval 0  partitions do NOT match
+  *   @retval 1  partitions match
+  *
+  * @note if match_anon is non-zero, then this function will return a
+  *       positive match for a zero-length partition string in the
+  *       command packet.
+  *
+  * @internal
+  */
+ static int 
+ FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
+ {
+     return ((match_anon && vcom->vop->partName[0] == 0) ||
+ 	    (strncmp(vcom->vop->partName, V_partition(vp)->name, 
+ 		     sizeof(vcom->vop->partName)) == 0));
+ }
+ 
+ 
  static void
  FSYNC_Drop(int fd)
  {
Index: openafs/src/vol/fssync.h
diff -c openafs/src/vol/fssync.h:1.5.2.3 openafs/src/vol/fssync.h:1.5.2.3.2.1
*** openafs/src/vol/fssync.h:1.5.2.3	Fri Mar 14 00:42:52 2008
--- openafs/src/vol/fssync.h	Thu Jun 12 15:23:52 2008
***************
*** 20,26 ****
  #define __fssync_h_
  
  
! #define FSYNC_PROTO_VERSION     2
  
  
  /**
--- 20,26 ----
  #define __fssync_h_
  
  
! #define FSYNC_PROTO_VERSION     3
  
  
  /**
***************
*** 67,72 ****
--- 67,74 ----
      FSYNC_NO_PENDING_VOL_OP   = SYNC_REASON_CODE_DECL(7), /**< no volume operation pending */
      FSYNC_VOL_PKG_ERROR       = SYNC_REASON_CODE_DECL(8), /**< error in the volume package */
      FSYNC_UNKNOWN_VNID        = SYNC_REASON_CODE_DECL(9), /**< vnode id not known by fileserver */
+     FSYNC_WRONG_PART          = SYNC_REASON_CODE_DECL(10),/**< volume attached on different partition */
+     FSYNC_BAD_STATE           = SYNC_REASON_CODE_DECL(11),/**< current volume state does not allow this operation */
      FSYNC_REASON_CODE_END
  };
  
Index: openafs/src/vol/partition.c
diff -c openafs/src/vol/partition.c:1.33.2.5 openafs/src/vol/partition.c:1.33.2.5.2.1
*** openafs/src/vol/partition.c:1.33.2.5	Wed Mar  5 16:53:30 2008
--- openafs/src/vol/partition.c	Thu Jun 12 15:23:52 2008
***************
*** 22,28 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/partition.c,v 1.33.2.5 2008/03/05 21:53:30 shadow Exp $");
  
  #include <ctype.h>
  #include <string.h>
--- 22,28 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/partition.c,v 1.33.2.5.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <ctype.h>
  #include <string.h>
***************
*** 281,288 ****
      VSetPartitionDiskUsage_r(dp);
  #ifdef AFS_DEMAND_ATTACH_FS
      AddPartitionToTable_r(dp);
!     queue_Init(&dp->vol_list);
      assert(pthread_cond_init(&dp->vol_list.cv, NULL) == 0);
  #endif /* AFS_DEMAND_ATTACH_FS */
  }
  
--- 281,290 ----
      VSetPartitionDiskUsage_r(dp);
  #ifdef AFS_DEMAND_ATTACH_FS
      AddPartitionToTable_r(dp);
!     queue_Init(&dp->vol_list.head);
      assert(pthread_cond_init(&dp->vol_list.cv, NULL) == 0);
+     dp->vol_list.len = 0;
+     dp->vol_list.busy = 0;
  #endif /* AFS_DEMAND_ATTACH_FS */
  }
  
***************
*** 1264,1272 ****
--- 1266,1293 ----
  }
  
  #ifdef AFS_DEMAND_ATTACH_FS
+ 
  /* XXX not sure this will work on AFS_NT40_ENV
   * needs to be tested!
   */
+ 
+ /**
+  * lookup a disk partition object by its index number.
+  *
+  * @param[in] id      partition index number
+  * @param[in] abortp  see abortp usage note below
+  *
+  * @return disk partition object
+  *   @retval NULL no such disk partition
+  *
+  * @note when abortp is non-zero, lookups which would return
+  *       NULL will result in an assertion failure
+  *
+  * @pre VOL_LOCK must be held
+  *
+  * @internal volume package internal use only
+  */
+ 
  struct DiskPartition64 * 
  VGetPartitionById_r(afs_int32 id, int abortp)
  {
***************
*** 1282,1287 ****
--- 1303,1321 ----
      return dp;
  }
  
+ /**
+  * lookup a disk partition object by its index number.
+  *
+  * @param[in] id      partition index number
+  * @param[in] abortp  see abortp usage note below
+  *
+  * @return disk partition object
+  *   @retval NULL no such disk partition
+  *
+  * @note when abortp is non-zero, lookups which would return
+  *       NULL will result in an assertion failure
+  */
+ 
  struct DiskPartition64 *
  VGetPartitionById(afs_int32 id, int abortp)
  {
Index: openafs/src/vol/purge.c
diff -c openafs/src/vol/purge.c:1.12.2.4 openafs/src/vol/purge.c:1.12.2.4.2.1
*** openafs/src/vol/purge.c:1.12.2.4	Wed Mar  5 16:53:30 2008
--- openafs/src/vol/purge.c	Thu Jun 12 15:23:52 2008
***************
*** 17,23 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/purge.c,v 1.12.2.4 2008/03/05 21:53:30 shadow Exp $");
  
  #include <stdio.h>
  #ifdef AFS_NT40_ENV
--- 17,23 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/purge.c,v 1.12.2.4.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <stdio.h>
  #ifdef AFS_NT40_ENV
***************
*** 66,71 ****
--- 66,75 ----
      struct DiskPartition64 *tpartp = vp->partition;
      char purgePath[MAXPATHLEN];
  
+     /* so VCheckDetach doesn't try to update the volume header and
+      * dump spurious errors into the logs */
+     V_inUse(vp) = 0;
+ 
      /* N.B.  it's important here to use the partition pointed to by the
       * volume header. This routine can, under some circumstances, be called
       * when two volumes with the same id exist on different partitions.
Index: openafs/src/vol/salvsync-server.c
diff -c openafs/src/vol/salvsync-server.c:1.1.4.9 openafs/src/vol/salvsync-server.c:1.1.4.9.2.1
*** openafs/src/vol/salvsync-server.c:1.1.4.9	Tue Apr  1 16:29:12 2008
--- openafs/src/vol/salvsync-server.c	Thu Jun 12 15:23:52 2008
***************
*** 27,33 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/salvsync-server.c,v 1.1.4.9 2008/04/01 20:29:12 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdio.h>
--- 27,33 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/salvsync-server.c,v 1.1.4.9.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <sys/types.h>
  #include <stdio.h>
***************
*** 380,386 ****
      sres.res = &res;
  
      SALV_cnt++;
!     if (SYNC_getCom(fd, &com)) {
  	Log("SALVSYNC_com:  read failed; dropping connection (cnt=%d)\n", SALV_cnt);
  	SALVSYNC_Drop(fd);
  	return;
--- 380,386 ----
      sres.res = &res;
  
      SALV_cnt++;
!     if (SYNC_getCom(&salvsync_server_state, fd, &com)) {
  	Log("SALVSYNC_com:  read failed; dropping connection (cnt=%d)\n", SALV_cnt);
  	SALVSYNC_Drop(fd);
  	return;
***************
*** 415,420 ****
--- 415,422 ----
  	goto respond;
      }
  
+     res.hdr.com_seq = com.hdr.com_seq;
+ 
      VOL_LOCK;
      switch (com.hdr.command) {
      case SALVSYNC_NOP:
***************
*** 449,455 ****
      VOL_UNLOCK;
  
   respond:
!     SYNC_putRes(fd, &res);
      if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
  	SALVSYNC_Drop(fd);
      }
--- 451,457 ----
      VOL_UNLOCK;
  
   respond:
!     SYNC_putRes(&salvsync_server_state, fd, &res);
      if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
  	SALVSYNC_Drop(fd);
      }
Index: openafs/src/vol/salvsync.h
diff -c openafs/src/vol/salvsync.h:1.1.4.2 openafs/src/vol/salvsync.h:1.1.4.2.2.1
*** openafs/src/vol/salvsync.h:1.1.4.2	Mon Feb  4 13:51:39 2008
--- openafs/src/vol/salvsync.h	Thu Jun 12 15:23:52 2008
***************
*** 12,18 ****
   * salvage server interface
   */
  #ifndef _AFS_VOL_SALVSYNC_H
! #define _AFS_VOL_SALVSYNC_H
  
  #define SALSRV_EXIT_VOLGROUP_LINK 10
  
--- 12,18 ----
   * salvage server interface
   */
  #ifndef _AFS_VOL_SALVSYNC_H
! #define _AFS_VOL_SALVSYNC_H 1
  
  #define SALSRV_EXIT_VOLGROUP_LINK 10
  
***************
*** 24,30 ****
  
  #define SALVSYNC_PROTO_VERSION_V1     1
  #define SALVSYNC_PROTO_VERSION_V2     2
! #define SALVSYNC_PROTO_VERSION        SALVSYNC_PROTO_VERSION_V2
  
  
  /** 
--- 24,31 ----
  
  #define SALVSYNC_PROTO_VERSION_V1     1
  #define SALVSYNC_PROTO_VERSION_V2     2
! #define SALVSYNC_PROTO_VERSION_V3     3
! #define SALVSYNC_PROTO_VERSION        SALVSYNC_PROTO_VERSION_V3
  
  
  /** 
Index: openafs/src/vol/vol-salvage.c
diff -c openafs/src/vol/vol-salvage.c:1.51.2.12 openafs/src/vol/vol-salvage.c:1.51.2.12.2.3
*** openafs/src/vol/vol-salvage.c:1.51.2.12	Mon Mar 17 12:05:28 2008
--- openafs/src/vol/vol-salvage.c	Sun Jun 22 22:49:26 2008
***************
*** 87,93 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/vol-salvage.c,v 1.51.2.12 2008/03/17 16:05:28 shadow Exp $");
  
  #ifndef AFS_NT40_ENV
  #include <sys/param.h>
--- 87,93 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/vol-salvage.c,v 1.51.2.12.2.3 2008/06/23 02:49:26 jaltman Exp $");
  
  #ifndef AFS_NT40_ENV
  #include <sys/param.h>
***************
*** 739,745 ****
  	if ((programType != salvageServer) && !VConnectFS()) {
  	    Abort("Couldn't connect to file server\n");
  	}
! 	AskOffline(singleVolumeNumber);
      } else {
  	if (!Showmode)
  	    Log("SALVAGING FILE SYSTEM PARTITION %s (device=%s%s)\n",
--- 739,745 ----
  	if ((programType != salvageServer) && !VConnectFS()) {
  	    Abort("Couldn't connect to file server\n");
  	}
! 	AskOffline(singleVolumeNumber, partP->name);
      } else {
  	if (!Showmode)
  	    Log("SALVAGING FILE SYSTEM PARTITION %s (device=%s%s)\n",
***************
*** 1289,1295 ****
  		    (void)afs_snprintf(nameShouldBe, sizeof nameShouldBe,
  				       VFORMAT, vsp->header.id);
  		    if (singleVolumeNumber)
! 			AskOffline(vsp->header.id);
  		    if (strcmp(nameShouldBe, dp->d_name)) {
  			if (!Showmode)
  			    Log("Volume header file %s is incorrectly named; %sdeleted (it will be recreated later, if necessary)\n", dp->d_name, (Testing ? "it would have been " : ""));
--- 1289,1295 ----
  		    (void)afs_snprintf(nameShouldBe, sizeof nameShouldBe,
  				       VFORMAT, vsp->header.id);
  		    if (singleVolumeNumber)
! 			AskOffline(vsp->header.id, fileSysPartition->name);
  		    if (strcmp(nameShouldBe, dp->d_name)) {
  			if (!Showmode)
  			    Log("Volume header file %s is incorrectly named; %sdeleted (it will be recreated later, if necessary)\n", dp->d_name, (Testing ? "it would have been " : ""));
***************
*** 2539,2565 ****
      } else {
  	if (ShowSuid && (vnodeEssence->modeBits & 06000))
  	    Log("FOUND suid/sgid file: %s/%s (%u.%u %05o) author %u (vnode %u dir %u)\n", dir->name ? dir->name : "??", name, vnodeEssence->owner, vnodeEssence->group, vnodeEssence->modeBits, vnodeEssence->author, vnodeNumber, dir->vnodeNumber);
! 	if (ShowMounts && (vnodeEssence->type == vSymlink)
  	    && !(vnodeEssence->modeBits & 0111)) {
  	    int code, size;
! 	    char buf[1024];
  	    IHandle_t *ihP;
  	    FdHandle_t *fdP;
  
  	    IH_INIT(ihP, fileSysDevice, dir->dirHandle.dirh_handle->ih_vid,
  		    vnodeEssence->InodeNumber);
  	    fdP = IH_OPEN(ihP);
! 	    assert(fdP != NULL);
  	    size = FDH_SIZE(fdP);
! 	    assert(size != -1);
! 	    memset(buf, 0, 1024);
  	    if (size > 1024)
  		size = 1024;
  	    code = FDH_READ(fdP, buf, size);
! 	    assert(code == size);
! 	    Log("In volume %u (%s) found mountpoint %s/%s to '%s'\n",
! 		dir->dirHandle.dirh_handle->ih_vid, dir->vname,
! 		dir->name ? dir->name : "??", name, buf);
  	    FDH_REALLYCLOSE(fdP);
  	    IH_RELEASE(ihP);
  	}
--- 2539,2585 ----
      } else {
  	if (ShowSuid && (vnodeEssence->modeBits & 06000))
  	    Log("FOUND suid/sgid file: %s/%s (%u.%u %05o) author %u (vnode %u dir %u)\n", dir->name ? dir->name : "??", name, vnodeEssence->owner, vnodeEssence->group, vnodeEssence->modeBits, vnodeEssence->author, vnodeNumber, dir->vnodeNumber);
! 	if (/* ShowMounts && */ (vnodeEssence->type == vSymlink)
  	    && !(vnodeEssence->modeBits & 0111)) {
  	    int code, size;
! 	    char buf[1025];
  	    IHandle_t *ihP;
  	    FdHandle_t *fdP;
  
  	    IH_INIT(ihP, fileSysDevice, dir->dirHandle.dirh_handle->ih_vid,
  		    vnodeEssence->InodeNumber);
  	    fdP = IH_OPEN(ihP);
! 	    if (fdP == NULL) {
! 		Log("ERROR %s could not open mount point vnode %u\n", dir->vname, vnodeNumber);
! 		IH_RELEASE(ihP);
! 		return;
! 	    }
  	    size = FDH_SIZE(fdP);
! 	    if (size < 0) {
! 		Log("ERROR %s mount point has invalid size %d, vnode %u\n", dir->vname, size, vnodeNumber);
! 		FDH_REALLYCLOSE(fdP);
! 		IH_RELEASE(ihP);
! 		return;
! 	    }
! 	
  	    if (size > 1024)
  		size = 1024;
  	    code = FDH_READ(fdP, buf, size);
! 	    if (code == size) {
! 		buf[size] = '\0';
! 		if ( (*buf != '#' && *buf != '%') || buf[strlen(buf)-1] != '.' ) {
! 		    Log("Volume %u (%s) mount point %s/%s to '%s' invalid, %s to symbolic link\n",
! 			dir->dirHandle.dirh_handle->ih_vid, dir->vname, dir->name ? dir->name : "??", name, buf,
! 			Testing ? "would convert" : "converted");
! 		    vnodeEssence->modeBits |= 0111;
! 		    vnodeEssence->changed = 1;
! 		} else if (ShowMounts) Log("In volume %u (%s) found mountpoint %s/%s to '%s'\n",
! 		    dir->dirHandle.dirh_handle->ih_vid, dir->vname,
! 		    dir->name ? dir->name : "??", name, buf);
! 	    } else {
! 		Log("Volume %s cound not read mount point vnode %u size %d code %d\n",
! 		    dir->vname, vnodeNumber, size, code);
! 	    }
  	    FDH_REALLYCLOSE(fdP);
  	    IH_RELEASE(ihP);
  	}
***************
*** 3035,3040 ****
--- 3055,3062 ----
  		    if (!Showmode) {
  			Log("Vnode %u: link count incorrect (was %d, %s %d)\n", vnodeNumber, oldCount, (Testing ? "would have changed to" : "now"), vnode.linkCount);
  		    }
+ 		} else {
+ 		    vnode.modeBits = vnp->modeBits;
  		}
  
  		vnode.dataVersion++;
***************
*** 3158,3169 ****
  
  
  void
! AskOffline(VolumeId volumeId)
  {
      afs_int32 code, i;
  
      for (i = 0; i < 3; i++) {
! 	code = FSYNC_VolOp(volumeId, NULL, FSYNC_VOL_OFF, FSYNC_SALVAGE, NULL);
  
  	if (code == SYNC_OK) {
  	    break;
--- 3180,3191 ----
  
  
  void
! AskOffline(VolumeId volumeId, char * partition)
  {
      afs_int32 code, i;
  
      for (i = 0; i < 3; i++) {
! 	code = FSYNC_VolOp(volumeId, partition, FSYNC_VOL_OFF, FSYNC_SALVAGE, NULL);
  
  	if (code == SYNC_OK) {
  	    break;
***************
*** 3372,3378 ****
      static char timestamp[20];
      lt = localtime(&clock);
      if (precision)
! 	(void)strftime(timestamp, 20, "%m/%d/%Y %T", lt);
      else
  	(void)strftime(timestamp, 20, "%m/%d/%Y %H:%M", lt);
      return timestamp;
--- 3394,3400 ----
      static char timestamp[20];
      lt = localtime(&clock);
      if (precision)
! 	(void)strftime(timestamp, 20, "%m/%d/%Y %H:%M:%S", lt);
      else
  	(void)strftime(timestamp, 20, "%m/%d/%Y %H:%M", lt);
      return timestamp;
Index: openafs/src/vol/vol-salvage.h
diff -c openafs/src/vol/vol-salvage.h:1.1.4.3 openafs/src/vol/vol-salvage.h:1.1.4.3.2.1
*** openafs/src/vol/vol-salvage.h:1.1.4.3	Wed Mar  5 16:53:30 2008
--- openafs/src/vol/vol-salvage.h	Thu Jun 12 15:23:52 2008
***************
*** 221,227 ****
  extern int Fork(void);
  extern int Wait(char *prog);
  extern char *ToString(char *s);
! extern void AskOffline(VolumeId volumeId);
  extern void AskOnline(VolumeId volumeId, char *partition);
  extern void CheckLogFile(char * log_path);
  #ifndef AFS_NT40_ENV
--- 221,227 ----
  extern int Fork(void);
  extern int Wait(char *prog);
  extern char *ToString(char *s);
! extern void AskOffline(VolumeId volumeId, char * partition);
  extern void AskOnline(VolumeId volumeId, char *partition);
  extern void CheckLogFile(char * log_path);
  #ifndef AFS_NT40_ENV
Index: openafs/src/vol/volume.c
diff -c openafs/src/vol/volume.c:1.43.2.20 openafs/src/vol/volume.c:1.43.2.20.2.1
*** openafs/src/vol/volume.c:1.43.2.20	Fri Apr  4 14:21:04 2008
--- openafs/src/vol/volume.c	Thu Jun 12 15:23:52 2008
***************
*** 22,28 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/volume.c,v 1.43.2.20 2008/04/04 18:21:04 shadow Exp $");
  
  #include <rx/xdr.h>
  #include <afs/afsint.h>
--- 22,28 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/vol/volume.c,v 1.43.2.20.2.1 2008/06/12 19:23:52 shadow Exp $");
  
  #include <rx/xdr.h>
  #include <afs/afsint.h>
***************
*** 389,394 ****
--- 389,400 ----
  static int VCheckSoftDetach(volatile Volume * vp, afs_uint32 thresh);
  static int VCheckSoftDetachCandidate(volatile Volume * vp, afs_uint32 thresh);
  static int VSoftDetachVolume_r(volatile Volume * vp, afs_uint32 thresh);
+ 
+ 
+ pthread_key_t VThread_key;
+ VThreadOptions_t VThread_defaults = {
+     0                           /**< allow salvsync */
+ };
  #endif /* AFS_DEMAND_ATTACH_FS */
  
  
***************
*** 445,450 ****
--- 451,457 ----
      } else {
  	VLRU_SetOptions(VLRU_SET_ENABLED, 0);
      }
+     assert(pthread_key_create(&VThread_key, NULL) == 0);
  #endif
  
  #ifdef AFS_PTHREAD_ENV
***************
*** 583,590 ****
  #ifdef FSSYNC_BUILD_CLIENT
      if (programType == volumeUtility && connect) {
  	if (!VConnectFS()) {
! 	    Log("Unable to connect to file server; aborted\n");
! 	    exit(1);
  	}
      }
  #ifdef AFS_DEMAND_ATTACH_FS
--- 590,597 ----
  #ifdef FSSYNC_BUILD_CLIENT
      if (programType == volumeUtility && connect) {
  	if (!VConnectFS()) {
! 	    Log("Unable to connect to file server; will retry at need\n");
! 	    /*exit(1);*/
  	}
      }
  #ifdef AFS_DEMAND_ATTACH_FS
***************
*** 1687,1693 ****
--- 1694,1702 ----
      /* link the volume with its associated vice partition */
      vp->device = partp->device;
      vp->partition = partp;
+ 
      vp->hashid = vid;
+     vp->specialStatus = 0;
  
      /* if we dropped the lock, reacquire the lock,
       * check for pre-attach races, and then add
***************
*** 1796,1807 ****
  	    VWaitExclusiveState_r(vp);
  
  	    /* at this point state must be one of:
! 	     *   UNATTACHED,
! 	     *   ATTACHED,
! 	     *   SHUTTING_DOWN,
! 	     *   GOING_OFFLINE,
! 	     *   SALVAGING,
! 	     *   ERROR
  	     */
  
  	    if (vp->specialStatus == VBUSY)
--- 1805,1816 ----
  	    VWaitExclusiveState_r(vp);
  
  	    /* at this point state must be one of:
! 	     *   - UNATTACHED
! 	     *   - ATTACHED
! 	     *   - SHUTTING_DOWN
! 	     *   - GOING_OFFLINE
! 	     *   - SALVAGING
! 	     *   - ERROR
  	     */
  
  	    if (vp->specialStatus == VBUSY)
***************
*** 2288,2294 ****
  	res.payload.buf = &vp->header->diskstuff;
  
  	if (FSYNC_VolOp(volumeId,
! 			VPartitionPath(partp),
  			FSYNC_VOL_QUERY_HDR,
  			FSYNC_WHATEVER,
  			&res) == SYNC_OK) {
--- 2297,2303 ----
  	res.payload.buf = &vp->header->diskstuff;
  
  	if (FSYNC_VolOp(volumeId,
! 			partp->name,
  			FSYNC_VOL_QUERY_HDR,
  			FSYNC_WHATEVER,
  			&res) == SYNC_OK) {
***************
*** 2506,2515 ****
  
      AddVolumeToHashTable(vp, V_id(vp));
  #ifdef AFS_DEMAND_ATTACH_FS
-     AddVolumeToVByPList_r(vp);
-     VLRU_Add_r(vp);
      if ((programType != fileServer) ||
  	(V_inUse(vp) == fileServer)) {
  	VChangeState_r(vp, VOL_STATE_ATTACHED);
      } else {
  	VChangeState_r(vp, VOL_STATE_UNATTACHED);
--- 2515,2524 ----
  
      AddVolumeToHashTable(vp, V_id(vp));
  #ifdef AFS_DEMAND_ATTACH_FS
      if ((programType != fileServer) ||
  	(V_inUse(vp) == fileServer)) {
+ 	AddVolumeToVByPList_r(vp);
+ 	VLRU_Add_r(vp);
  	VChangeState_r(vp, VOL_STATE_ATTACHED);
      } else {
  	VChangeState_r(vp, VOL_STATE_UNATTACHED);
***************
*** 2698,2703 ****
--- 2707,2726 ----
      Volume *avp, * rvp = hint;
  #endif
  
+     /* 
+      * if VInit is zero, the volume package dynamic
+      * data structures have not been initialized yet,
+      * and we must immediately return an error
+      */
+     if (VInit == 0) {
+ 	vp = NULL;
+ 	*ec = VOFFLINE;
+ 	if (client_ec) {
+ 	    *client_ec = VOFFLINE;
+ 	}
+ 	goto not_inited;
+     }
+ 
  #ifdef AFS_DEMAND_ATTACH_FS
      if (rvp) {
  	VCreateReservation_r(rvp);
***************
*** 2755,2762 ****
  
  	/* short circuit with VNOVOL in the following circumstances:
  	 *
! 	 *   VOL_STATE_ERROR
! 	 *   VOL_STATE_SHUTTING_DOWN
  	 */
  	if ((V_attachState(vp) == VOL_STATE_ERROR) ||
  	    (V_attachState(vp) == VOL_STATE_SHUTTING_DOWN)) {
--- 2778,2785 ----
  
  	/* short circuit with VNOVOL in the following circumstances:
  	 *
! 	 *   - VOL_STATE_ERROR
! 	 *   - VOL_STATE_SHUTTING_DOWN
  	 */
  	if ((V_attachState(vp) == VOL_STATE_ERROR) ||
  	    (V_attachState(vp) == VOL_STATE_SHUTTING_DOWN)) {
***************
*** 2768,2787 ****
  	/*
  	 * short circuit with VOFFLINE in the following circumstances:
  	 *
! 	 *   VOL_STATE_UNATTACHED
  	 */
         if (V_attachState(vp) == VOL_STATE_UNATTACHED) {
!            *ec = VOFFLINE;
             vp = NULL;
             break;
         }
  
  	/* allowable states:
! 	 *   UNATTACHED
! 	 *   PREATTACHED
! 	 *   ATTACHED
! 	 *   GOING_OFFLINE
! 	 *   SALVAGING
  	 */
  
  	if (vp->salvage.requested) {
--- 2791,2813 ----
  	/*
  	 * short circuit with VOFFLINE in the following circumstances:
  	 *
! 	 *   - VOL_STATE_UNATTACHED
  	 */
         if (V_attachState(vp) == VOL_STATE_UNATTACHED) {
! 	   if (vp->specialStatus) {
! 	       *ec = vp->specialStatus;
! 	   } else {
! 	       *ec = VOFFLINE;
! 	   }
             vp = NULL;
             break;
         }
  
  	/* allowable states:
! 	 *   - PREATTACHED
! 	 *   - ATTACHED
! 	 *   - GOING_OFFLINE
! 	 *   - SALVAGING
  	 */
  
  	if (vp->salvage.requested) {
***************
*** 2869,2888 ****
  	 * this test MUST happen after the volume header is loaded
  	 */
  	if (vp->pending_vol_op && !VVolOpLeaveOnline_r(vp, vp->pending_vol_op)) {
! 	    if (client_ec) {
! 		/* see CheckVnode() in afsfileprocs.c for an explanation
! 		 * of this error code logic */
! 		afs_uint32 now = FT_ApproxTime();
! 		if ((vp->stats.last_vol_op + (10 * 60)) >= now) {
! 		    *client_ec = VBUSY;
! 		} else {
! 		    *client_ec = VRESTARTING;
! 		}
! 	    }
! 	    *ec = VOFFLINE;
! 	    ReleaseVolumeHeader(vp->header);
! 	    vp = NULL;
! 	    break;
  	}
  #endif /* AFS_DEMAND_ATTACH_FS */
  	
--- 2895,2928 ----
  	 * this test MUST happen after the volume header is loaded
  	 */
  	if (vp->pending_vol_op && !VVolOpLeaveOnline_r(vp, vp->pending_vol_op)) {
! 	   /* 
! 	    * volume cannot remain online during this volume operation.
! 	    * notify client. 
! 	    */
! 	   if (vp->specialStatus) {
! 	       /*
! 		* special status codes outrank normal VOFFLINE code
! 		*/
! 	       *ec = vp->specialStatus;
! 	       if (client_ec) {
! 		   *client_ec = vp->specialStatus;
! 	       }
! 	   } else {
! 	       if (client_ec) {
! 		   /* see CheckVnode() in afsfileprocs.c for an explanation
! 		    * of this error code logic */
! 		   afs_uint32 now = FT_ApproxTime();
! 		   if ((vp->stats.last_vol_op + (10 * 60)) >= now) {
! 		       *client_ec = VBUSY;
! 		   } else {
! 		       *client_ec = VRESTARTING;
! 		   }
! 	       }
! 	       *ec = VOFFLINE;
! 	   }
! 	   ReleaseVolumeHeader(vp->header);
! 	   vp = NULL;
! 	   break;
  	}
  #endif /* AFS_DEMAND_ATTACH_FS */
  	
***************
*** 2950,2955 ****
--- 2990,2996 ----
      }
  #endif /* AFS_DEMAND_ATTACH_FS */
  
+  not_inited:
      assert(vp || *ec);
      return vp;
  }
***************
*** 3456,3463 ****
  	    V_inUse(vp) = 0;
  	    VUpdateVolume_r(&ec, vp, VOL_UPDATE_NOFORCEOFF);
  	    if (ec) {
! 		Log("VCheckDetach: failed to clear inUse failed during detachment of volid %u\n",
! 		    vp->hashid);
  	    }
  	}
  	VReleaseVolumeHandles_r(vp);
--- 3497,3504 ----
  	    V_inUse(vp) = 0;
  	    VUpdateVolume_r(&ec, vp, VOL_UPDATE_NOFORCEOFF);
  	    if (ec) {
! 		Log("VCheckDetach: volume header update for volume %u "
! 		    "failed with errno %d\n", vp->hashid, errno);
  	    }
  	}
  	VReleaseVolumeHandles_r(vp);
***************
*** 3489,3496 ****
  	    V_inUse(vp) = 0;
  	    VUpdateVolume_r(&ec, vp, VOL_UPDATE_NOFORCEOFF);
  	    if (ec) {
! 		Log("VCheckDetach: failed to clear inUse failed during detachment of volid %u\n",
! 		    vp->hashid);
  	    }
  	}
  	VReleaseVolumeHandles_r(vp);
--- 3530,3537 ----
  	    V_inUse(vp) = 0;
  	    VUpdateVolume_r(&ec, vp, VOL_UPDATE_NOFORCEOFF);
  	    if (ec) {
! 		Log("VCheckDetach: volume header update for volume %u failed with errno %d\n",
! 		    vp->hashid, errno);
  	    }
  	}
  	VReleaseVolumeHandles_r(vp);
***************
*** 3983,3988 ****
--- 4024,4030 ----
      int code, ret=0;
  #ifdef SALVSYNC_BUILD_CLIENT
      VolState state_save;
+     VThreadOptions_t * thread_opts;
      char partName[16];
  
      if (vp->nWaiters || vp->nUsers) {
***************
*** 3993,3998 ****
--- 4035,4055 ----
      if (vp->stats.salvages >= SALVAGE_COUNT_MAX)
  	return 1;
  
+     /*
+      * don't perform salvsync ops on certain threads
+      */
+     thread_opts = pthread_getspecific(VThread_key);
+     if (thread_opts == NULL) {
+ 	thread_opts = &VThread_defaults;
+     }
+     if (thread_opts->disallow_salvsync) {
+ 	return 1;
+     }
+ 
+     /*
+      * XXX the scheduling process should really be done asynchronously
+      *     to avoid fssync deadlocks
+      */
      if (!vp->salvage.scheduled) {
  	/* if we haven't previously scheduled a salvage, do so now 
  	 *
***************
*** 4004,4010 ****
  	 */
  	strlcpy(partName, VPartitionPath(vp->partition), sizeof(partName));
  	state_save = VChangeState_r(vp, VOL_STATE_SALVSYNC_REQ);
- 	V_attachFlags(vp) |= VOL_IS_BUSY;
  	VOL_UNLOCK;
  
  	/* can't use V_id() since there's no guarantee
--- 4061,4066 ----
***************
*** 4017,4023 ****
  				      NULL);
  	VOL_LOCK;
  	VChangeState_r(vp, state_save);
- 	V_attachFlags(vp) &= ~(VOL_IS_BUSY);
  
  	if (code == SYNC_OK) {
  	    vp->salvage.scheduled = 1;
--- 4073,4078 ----
***************
*** 4055,4063 ****
   *
   * @pre VOL_LOCK is held.
   *
!  * @post salvageserver is sent a request to cancel the volume salvage
!  *
!  * @todo should set exclusive state and drop glock around salvsync call
   *
   * @internal volume package internal use only.
   */
--- 4110,4117 ----
   *
   * @pre VOL_LOCK is held.
   *
!  * @post salvageserver is sent a request to cancel the volume salvage.
!  *       volume is transitioned to a hard error state.
   *
   * @internal volume package internal use only.
   */
***************
*** 4068,4081 ****
--- 4122,4145 ----
  
  #ifdef SALVSYNC_BUILD_CLIENT
      if (vp->salvage.scheduled) {
+ 	VChangeState_r(vp, VOL_STATE_SALVSYNC_REQ);
+ 	VOL_UNLOCK;
+ 
+ 	/* can't use V_id() since there's no guarantee
+ 	 * we have the disk data header at this point */
  	code = SALVSYNC_SalvageVolume(vp->hashid,
  				      VPartitionPath(vp->partition),
  				      SALVSYNC_CANCEL,
  				      reason,
  				      0,
  				      NULL);
+ 
+ 	VOL_LOCK;
+ 	VChangeState_r(vp, VOL_STATE_ERROR);
+ 
  	if (code == SYNC_OK) {
  	    vp->salvage.scheduled = 0;
+ 	    vp->salvage.requested = 0;
  	} else {
  	    ret = 1;
  	}
***************
*** 5620,5626 ****
  		min_delay = 0;
  		min_idx = i;
  		overdue = 1;
- 		break;
  	    }
  	}
  
--- 5684,5689 ----
Index: openafs/src/vol/volume.h
diff -c openafs/src/vol/volume.h:1.19.2.5 openafs/src/vol/volume.h:1.19.2.5.2.1
*** openafs/src/vol/volume.h:1.19.2.5	Fri Apr  4 15:58:45 2008
--- openafs/src/vol/volume.h	Thu Jun 12 15:23:53 2008
***************
*** 222,227 ****
--- 222,238 ----
  #define VLRU_DEFAULT_OFFLINE_INTERVAL (60*2) /* 2 minutes */
  #define VLRU_DEFAULT_OFFLINE_MAX 8 /* 8 volumes */
  
+ 
+ /**
+  * DAFS thread-specific options structure
+  */
+ typedef struct VThreadOptions {
+      int disallow_salvsync;     /**< whether or not salvsync calls are allowed
+ 				 *   on this thread (deadlock prevention). */
+ } VThreadOptions_t;
+ extern pthread_key_t VThread_key;
+ extern VThreadOptions_t VThread_defaults;
+ 
  #endif /* AFS_DEMAND_ATTACH_FS */
  
  
Index: openafs/src/volser/volprocs.c
diff -c openafs/src/volser/volprocs.c:1.42.2.14 openafs/src/volser/volprocs.c:1.42.2.14.2.1
*** openafs/src/volser/volprocs.c:1.42.2.14	Mon Mar 17 13:14:11 2008
--- openafs/src/volser/volprocs.c	Thu Jun 12 15:23:53 2008
***************
*** 13,19 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/volprocs.c,v 1.42.2.14 2008/03/17 17:14:11 shadow Exp $");
  
  #include <stdio.h>
  #include <sys/types.h>
--- 13,19 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/volser/volprocs.c,v 1.42.2.14.2.1 2008/06/12 19:23:53 shadow Exp $");
  
  #include <stdio.h>
  #include <sys/types.h>
***************
*** 352,358 ****
  afs_int32
  VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_int32 avolID)
  {
-     register char *tp;
      char partName[50];
      afs_int32 error;
      register afs_int32 code;
--- 352,357 ----
***************
*** 365,374 ****
      if (DoLogging)
  	Log("%s is executing VolNukeVolume %u\n", caller, avolID);
  
!     tp = volutil_PartitionName(apartID);
!     if (!tp)
  	return VOLSERNOVOL;
-     strcpy(partName, tp);	/* remember it for later */
      /* we first try to attach the volume in update mode, so that the file
       * server doesn't try to use it (and abort) while (or after) we delete it.
       * If we don't get the volume, that's fine, too.  We just won't put it back.
--- 364,371 ----
      if (DoLogging)
  	Log("%s is executing VolNukeVolume %u\n", caller, avolID);
  
!     if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
  	return VOLSERNOVOL;
      /* we first try to attach the volume in update mode, so that the file
       * server doesn't try to use it (and abort) while (or after) we delete it.
       * If we don't get the volume, that's fine, too.  We just won't put it back.
***************
*** 1448,1453 ****
--- 1445,1451 ----
  {
      register struct volser_trans *tt;
      char caller[MAXKTCNAMELEN];
+     char partName[16];
  
      if (!afsconf_SuperUser(tdir, acid, caller))
  	return VOLSERBAD_ACCESS;	/*not a super user */
***************
*** 1462,1468 ****
      }
      strcpy(tt->lastProcName, "SetForwarding");
      tt->rxCallPtr = acid;
!     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_MOVE, anewsite, NULL);
      tt->rxCallPtr = (struct rx_call *)0;
      if (TRELE(tt))
  	return VOLSERTRELE_ERROR;
--- 1460,1469 ----
      }
      strcpy(tt->lastProcName, "SetForwarding");
      tt->rxCallPtr = acid;
!     if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
! 	partName[0] = '\0';
!     }
!     FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
      tt->rxCallPtr = (struct rx_call *)0;
      if (TRELE(tt))
  	return VOLSERTRELE_ERROR;
***************
*** 1830,1835 ****
--- 1831,1839 ----
   *
   * @pre handle object must have a valid pointer and enumeration value
   *
+  * @note passing a NULL value for vp means that the fileserver doesn't
+  *       know about this particular volume, thus implying it is offline.
+  *
   * @return operation status
   *   @retval 0 success
   *   @retval 1 failure
***************
*** 1871,1877 ****
       * along with the blessed and inService flags from the header.
       *   -- tkeiser 11/27/2007
       */
!     if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
  	VIsErrorState(V_attachState(vp)) ||
  	!hdr->inService ||
  	!hdr->blessed) {
--- 1875,1882 ----
       * along with the blessed and inService flags from the header.
       *   -- tkeiser 11/27/2007
       */
!     if (!vp ||
! 	(V_attachState(vp) == VOL_STATE_UNATTACHED) ||
  	VIsErrorState(V_attachState(vp)) ||
  	!hdr->inService ||
  	!hdr->blessed) {
***************
*** 1893,1899 ****
  
  #ifdef AFS_DEMAND_ATTACH_FS
  	/* see comment above where we set inUse bit */
! 	if (hdr->needsSalvaged || VIsErrorState(V_attachState(vp))) {
  	    handle->volinfo_ptr.base->needsSalvaged = 1;
  	} else {
  	    handle->volinfo_ptr.base->needsSalvaged = 0;
--- 1898,1905 ----
  
  #ifdef AFS_DEMAND_ATTACH_FS
  	/* see comment above where we set inUse bit */
! 	if (hdr->needsSalvaged || 
! 	    (vp && VIsErrorState(V_attachState(vp)))) {
  	    handle->volinfo_ptr.base->needsSalvaged = 1;
  	} else {
  	    handle->volinfo_ptr.base->needsSalvaged = 0;
***************
*** 1943,1970 ****
   * get struct Volume out of the fileserver.
   *
   * @param[in] volumeId  volumeId for which we want state information
!  * @param[out] vp       pointer to Volume object
   *
   * @return operation status
!  *   @retval 0 success
!  *   @retval nonzero failure
   */
  static int
! GetVolObject(afs_uint32 volumeId, Volume * vp)
  {
      int code;
      SYNC_response res;
  
      res.hdr.response_len = sizeof(res.hdr);
!     res.payload.buf = vp;
!     res.payload.len = sizeof(*vp);
  
      code = FSYNC_VolOp(volumeId,
! 		       "",
  		       FSYNC_VOL_QUERY,
  		       0,
  		       &res);
  
      return code;
  }
  
--- 1949,1992 ----
   * get struct Volume out of the fileserver.
   *
   * @param[in] volumeId  volumeId for which we want state information
!  * @param[in] pname     partition name string
!  * @param[inout] vp     pointer to pointer to Volume object which 
!  *                      will be populated (see note)
   *
   * @return operation status
!  *   @retval 0         success
!  *   @retval non-zero  failure
!  *
!  * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
!  *
!  * @internal
   */
  static int
! GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
  {
      int code;
      SYNC_response res;
  
      res.hdr.response_len = sizeof(res.hdr);
!     res.payload.buf = *vp;
!     res.payload.len = sizeof(Volume);
  
      code = FSYNC_VolOp(volumeId,
! 		       pname,
  		       FSYNC_VOL_QUERY,
  		       0,
  		       &res);
  
+     if (code != SYNC_OK) {
+ 	switch (res.hdr.reason) {
+ 	case FSYNC_WRONG_PART:
+ 	case FSYNC_UNKNOWN_VOLID:
+ 	    *vp = NULL;
+ 	    code = SYNC_OK;
+ 	    break;
+ 	}
+     }
+ 
      return code;
  }
  
***************
*** 2001,2009 ****
  	   vol_info_list_mode_t mode)
  {
      int code = -1;
      afs_int32 error;
      struct volser_trans *ttc = NULL;
!     struct Volume fs_tv, *tv = NULL;
  
      ttc = NewTrans(volumeId, partId);
      if (!ttc) {
--- 2023,2032 ----
  	   vol_info_list_mode_t mode)
  {
      int code = -1;
+     int reason;
      afs_int32 error;
      struct volser_trans *ttc = NULL;
!     struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf, *tv = NULL;
  
      ttc = NewTrans(volumeId, partId);
      if (!ttc) {
***************
*** 2050,2062 ****
      }
  
  #ifdef AFS_DEMAND_ATTACH_FS
!     if (GetVolObject(volumeId, &fs_tv)) {
  	goto drop;
      }
  #endif
  
      /* ok, we have all the data we need; fill in the on-wire struct */
!     code = FillVolInfo(&fs_tv, &tv->header->diskstuff, handle);
  
  
   drop:
--- 2073,2085 ----
      }
  
  #ifdef AFS_DEMAND_ATTACH_FS
!     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK) {
  	goto drop;
      }
  #endif
  
      /* ok, we have all the data we need; fill in the on-wire struct */
!     code = FillVolInfo(fs_tv, &tv->header->diskstuff, handle);
  
  
   drop:
