Windows: AFSVolSync creationDate based readonly volume versioning
[openafs.git] / src / WINNT / afsd / cm_vnodeops.c
index 391f55c..4a13e40 100644 (file)
@@ -147,7 +147,7 @@ long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
 
         if (code == 0) {
-            cm_Unlock(scp, sLockType, LOffset, LLength, key, userp, reqp);
+            cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp);
         } else {
             /* In this case, we allow the file open to go through even
                though we can't enforce mandatory locking on the
@@ -254,7 +254,7 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
            (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
            if (!*ldpp) {
                code = ENOMEM;
-               goto _syncopdone;
+               goto _done;
            }
 
            (*ldpp)->key = key;
@@ -288,9 +288,6 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         goto _done;
     }
 
-  _syncopdone:
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
-
  _done:
     lock_ReleaseWrite(&scp->rw);
 
@@ -302,14 +299,15 @@ extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *req
                               cm_lock_data_t ** ldpp)
 {
     osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
+    lock_ObtainWrite(&scp->rw);
     if (*ldpp) {
-       lock_ObtainWrite(&scp->rw);
        cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength, 
-                 (*ldpp)->key, userp, reqp);
-       lock_ReleaseWrite(&scp->rw);
+                 (*ldpp)->key, 0, userp, reqp);
        free(*ldpp);
        *ldpp = NULL;
     }
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+    lock_ReleaseWrite(&scp->rw);
     return 0;
 }
 /*
@@ -341,7 +339,8 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_DELETE,
                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
-    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (!code)
+        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     lock_ReleaseWrite(&scp->rw);
     if (code)
         return code;
@@ -352,7 +351,7 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
         return code;
 
     thyper.HighPart = 0; thyper.LowPart = 0;
-    code = buf_Get(scp, &thyper, &bufferp);
+    code = buf_Get(scp, &thyper, reqp, &bufferp);
     if (code)
         return code;
 
@@ -591,7 +590,7 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
                 bufferp = NULL;
             }
 
-            code = buf_Get(scp, &thyper, &bufferp);
+            code = buf_Get(scp, &thyper, reqp, &bufferp);
             if (code) {
                 /* if buf_Get() fails we do not have a buffer object to lock */
                 bufferp = NULL;
@@ -728,7 +727,11 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 
     sp = (cm_lookupSearch_t *) rockp;
 
-    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        /* Can't normalize FS string. */
+        return 0;
+    }
+
     if (sp->caseFold)
         match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
     else
@@ -805,68 +808,79 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 {
     long code;
-    cm_buf_t *bufp;
+    cm_buf_t *bufp = NULL;
     osi_hyper_t thyper;
     int tlen;
 
     if (scp->mountPointStringp[0]) 
         return 0;
         
-    /* otherwise, we have to read it in */
-    lock_ReleaseWrite(&scp->rw);
-
-    thyper.LowPart = thyper.HighPart = 0;
-    code = buf_Get(scp, &thyper, &bufp);
+#ifdef AFS_FREELANCE_CLIENT
+    /* File servers do not have data for freelance entries */
+    if (cm_freelanceEnabled &&
+        scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+        scp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+    {       
+        code = cm_FreelanceFetchMountPointString(scp);
+    } else 
+#endif /* AFS_FREELANCE_CLIENT */        
+    {
+        /* otherwise, we have to read it in */
+        lock_ReleaseWrite(&scp->rw);
 
-    lock_ObtainWrite(&scp->rw);
-    if (code)
-        return code;
+        thyper.LowPart = thyper.HighPart = 0;
+        code = buf_Get(scp, &thyper, reqp, &bufp);
 
-    while (1) {
-        code = cm_SyncOp(scp, bufp, userp, reqp, 0,
-                          CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
+        lock_ObtainWrite(&scp->rw);
         if (code)
-            goto done;
+            return code;
 
-       cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+        while (1) {
+            code = cm_SyncOp(scp, bufp, userp, reqp, 0,
+                              CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
+            if (code)
+                goto done;
 
-        if (cm_HaveBuffer(scp, bufp, 0)) 
-            break;
+            cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
 
-        /* otherwise load buffer */
-        code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
-        if (code)
+            if (cm_HaveBuffer(scp, bufp, 0)) 
+                break;
+
+            /* otherwise load buffer */
+            code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
+            if (code)
+                goto done;
+        }
+        /* locked, has callback, has valid data in buffer */
+        if ((tlen = scp->length.LowPart) > MOUNTPOINTLEN - 1) 
+            return CM_ERROR_TOOBIG;
+        if (tlen <= 0) {
+            code = CM_ERROR_INVAL;
             goto done;
-    }
-    /* locked, has callback, has valid data in buffer */
-    if ((tlen = scp->length.LowPart) > MOUNTPOINTLEN - 1) 
-        return CM_ERROR_TOOBIG;
-    if (tlen <= 0) {
-        code = CM_ERROR_INVAL;
-        goto done;
-    }
+        }
 
-    /* someone else did the work while we were out */
-    if (scp->mountPointStringp[0]) {
-        code = 0;
-        goto done;
-    }
+        /* someone else did the work while we were out */
+        if (scp->mountPointStringp[0]) {
+            code = 0;
+            goto done;
+        }
 
-    /* otherwise, copy out the link */
-    memcpy(scp->mountPointStringp, bufp->datap, tlen);
+        /* otherwise, copy out the link */
+        memcpy(scp->mountPointStringp, bufp->datap, tlen);
 
-    /* now make it null-terminated.  Note that the original contents of a
-     * link that is a mount point is "#volname." where "." is there just to
-     * be turned into a null.  That is, we can trash the last char of the
-     * link without damaging the vol name.  This is a stupid convention,
-     * but that's the protocol.
-     */
-    scp->mountPointStringp[tlen-1] = 0;
-    code = 0;
+        /* now make it null-terminated.  Note that the original contents of a
+         * link that is a mount point is "#volname." where "." is there just to
+         * be turned into a null.  That is, we can trash the last char of the
+         * link without damaging the vol name.  This is a stupid convention,
+         * but that's the protocol.
+         */
+        scp->mountPointStringp[tlen-1] = 0;
+        code = 0;
 
-  done:
-    if (bufp) 
-        buf_Release(bufp);
+      done:
+        if (bufp) 
+            buf_Release(bufp);
+    }
     return code;
 }
 
@@ -890,6 +904,8 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
     size_t vnLength;
     int targetType;
 
+    *outScpp = NULL;
+
     if (scp->mountRootFid.cell != 0 && scp->mountRootGen >= cm_data.mountRootGen) {
         tfid = scp->mountRootFid;
         lock_ReleaseWrite(&scp->rw);
@@ -920,7 +936,21 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
         /* normal mt pt */
         volNamep = cm_FsStrDup(mpNamep + 1);
 
-        cellp = cm_FindCellByID(scp->fid.cell, 0);
+#ifdef AFS_FREELANCE_CLIENT
+        /* 
+         * Mount points in the Freelance cell should default
+         * to the workstation cell.
+         */
+        if (cm_freelanceEnabled &&
+             scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+             scp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+        {       
+            fschar_t rootCellName[256]="";
+            cm_GetRootCellName(rootCellName);
+            cellp = cm_GetCell(rootCellName, 0);
+        } else 
+#endif /* AFS_FREELANCE_CLIENT */        
+            cellp = cm_FindCellByID(scp->fid.cell, 0);
     }
 
     if (!cellp) {
@@ -1012,7 +1042,7 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
 }       
 
 long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
-                       cm_req_t *reqp, cm_scache_t **outpScpp)
+                       cm_req_t *reqp, cm_scache_t **outScpp)
 {
     long code;
     int dnlcHit = 1;   /* did we hit in the dnlc? yes, we did */
@@ -1023,6 +1053,8 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
     normchar_t *nnamep = NULL;
     fschar_t *fnamep = NULL;
 
+    *outScpp = NULL;
+
     memset(&rock, 0, sizeof(rock));
 
     if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
@@ -1037,7 +1069,15 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
     }
 
     nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+    if (!nnamep) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
     fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+    if (!fnamep) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
 
     if (flags & CM_FLAG_NOMOUNTCHASE) {
         /* In this case, we should go and call cm_Dir* functions
@@ -1126,7 +1166,7 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
                  cm_ClientStrCmpI(cnamep, _C("ipc$"))) 
         {
             /* nonexistent dir on freelance root, so add it */
-            fschar_t fullname[200] = ".";
+            fschar_t fullname[CELL_MAXNAMELEN + 1] = ".";  /* +1 so that when we skip the . the size is still CELL_MAXNAMELEN */
             int  found = 0;
 
             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %S", 
@@ -1162,7 +1202,7 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
                         code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
                 }
             }
-            if (!found || code < 0) {   /* add mount point failed, so give up */
+            if (!found || code) {   /* add mount point failed, so give up */
                 if (flags & CM_FLAG_CHECKPATH)
                     code = CM_ERROR_NOSUCHPATH;
                 else
@@ -1221,7 +1261,7 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
     }
 
     /* copy back pointer */
-    *outpScpp = tscp;
+    *outScpp = tscp;
 
     /* insert scache in dnlc */
     if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
@@ -1232,7 +1272,8 @@ long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_u
             if (nnamep) 
                 free(nnamep);
             nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
-            cm_dnlcEnter(dscp, nnamep, tscp);
+            if (nnamep)
+                cm_dnlcEnter(dscp, nnamep, tscp);
         }
         lock_ReleaseRead(&dscp->rw);
     }
@@ -1280,7 +1321,7 @@ int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, uns
 }   
 
 long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
-                                cm_req_t *reqp, cm_scache_t ** outpScpp)
+                                cm_req_t *reqp, cm_scache_t ** outScpp)
 {
     afs_uint32    code = 0;
     fschar_t      cellName[CELL_MAXNAMELEN];
@@ -1312,7 +1353,7 @@ long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * us
 
      */
 
-    fnamep = cm_ClientStringToFsStringAlloc(namep, cm_ClientStrLen(namep), NULL);
+    fnamep = cm_ClientStringToFsStringAlloc(namep, -1, NULL);
     cp = fnamep + CM_PREFIX_VOL_CCH; /* cp points to cell name, hopefully */
     tp = cm_FsStrChr(cp, '%');
     if (tp == NULL)
@@ -1369,7 +1410,7 @@ long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * us
 
     cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
 
-    code = cm_GetSCache(&fid, outpScpp, userp, reqp);
+    code = cm_GetSCache(&fid, outScpp, userp, reqp);
 
   _exit_cleanup:
     if (fnamep)
@@ -1390,10 +1431,10 @@ long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * us
 
 #ifdef DEBUG_REFCOUNT
 long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
-               cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
+               cm_req_t *reqp, cm_scache_t **outScpp, char * file, long line)
 #else
 long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
-               cm_req_t *reqp, cm_scache_t **outpScpp)
+               cm_req_t *reqp, cm_scache_t **outScpp)
 #endif
 {
     long code;
@@ -1415,7 +1456,7 @@ long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *us
 
     if (dscp == cm_data.rootSCachep &&
         cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) == 0) {
-        return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outpScpp);
+        return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outScpp);
     }
 
     if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
@@ -1429,7 +1470,7 @@ long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *us
 #endif
 
                 if (code == 0) {
-                    *outpScpp = scp;
+                    *outScpp = scp;
                     return 0;
                 }
                 if (scp) {
@@ -1442,7 +1483,7 @@ long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *us
                 afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
                 osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
 #endif
-                *outpScpp = scp;
+                *outScpp = scp;
                 return code;
             }
         }
@@ -1452,7 +1493,7 @@ long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *us
         afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
         osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
 #endif
-        *outpScpp = scp;
+        *outScpp = scp;
         return code;
     }
 
@@ -1492,11 +1533,13 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
     int sflags;
     AFSFetchStatus newDirStatus;
     AFSVolSync volSync;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t dirop;
     cm_scache_t *scp = NULL;
     int free_fnamep = FALSE;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     if (fnamep == NULL) {
         code = -1;
 #ifdef USE_BPLUS
@@ -1545,10 +1588,10 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
         if (code)
             continue;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_RemoveFile(callp, &afsFid, fnamep,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_RemoveFile(rxconnp, &afsFid, fnamep,
                                 &newDirStatus, &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
     code = cm_MapRPCError(code, reqp);
@@ -1566,7 +1609,7 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
     cm_dnlcRemove(dscp, cnamep);
     cm_SyncOpDone(dscp, NULL, sflags);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+        cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
     } else if (code == CM_ERROR_NOSUCHFILE) {
        /* windows would not have allowed the request to delete the file 
         * if it did not believe the file existed.  therefore, we must 
@@ -1588,7 +1631,9 @@ long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
         cm_ReleaseSCache(scp);
         if (code == 0) {
            lock_ObtainWrite(&scp->rw);
-            scp->flags |= CM_SCACHEFLAG_DELETED;
+            if (--scp->linkCount == 0)
+                scp->flags |= CM_SCACHEFLAG_DELETED;
+            cm_DiscardSCache(scp);
            lock_ReleaseWrite(&scp->rw);
         }
     }
@@ -1612,51 +1657,64 @@ long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
 
     lock_AssertWrite(&linkScp->rw);
     if (!linkScp->mountPointStringp[0]) {
-        /* read the link data */
-        lock_ReleaseWrite(&linkScp->rw);
-        thyper.LowPart = thyper.HighPart = 0;
-        code = buf_Get(linkScp, &thyper, &bufp);
-        lock_ObtainWrite(&linkScp->rw);
-        if (code) 
-            return code;
-        while (1) {
-            code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
-                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
-            if (code) {
-                buf_Release(bufp);
+        
+#ifdef AFS_FREELANCE_CLIENT
+       /* File servers do not have data for freelance entries */
+        if (cm_freelanceEnabled &&
+            linkScp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+            linkScp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+        {
+            code = cm_FreelanceFetchMountPointString(linkScp);
+        } else 
+#endif /* AFS_FREELANCE_CLIENT */        
+        {
+            /* read the link data from the file server*/
+            lock_ReleaseWrite(&linkScp->rw);
+            thyper.LowPart = thyper.HighPart = 0;
+            code = buf_Get(linkScp, &thyper, reqp, &bufp);
+            lock_ObtainWrite(&linkScp->rw);
+            if (code) 
                 return code;
-            }
-           cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+            while (1) {
+                code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
+                                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+                if (code) {
+                    buf_Release(bufp);
+                    return code;
+                }
+                cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
 
-            if (cm_HaveBuffer(linkScp, bufp, 0)) 
-                break;
+                if (cm_HaveBuffer(linkScp, bufp, 0)) 
+                    break;
 
-            code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
-            if (code) {
+                code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
+                if (code) {
+                    buf_Release(bufp);
+                    return code;
+                }
+            } /* while loop to get the data */
+
+            /* now if we still have no link read in,
+             * copy the data from the buffer */
+            if ((temp = linkScp->length.LowPart) >= MOUNTPOINTLEN) {
                 buf_Release(bufp);
-                return code;
+                return CM_ERROR_TOOBIG;
+            }       
+
+            /* otherwise, it fits; make sure it is still null (could have
+             * lost race with someone else referencing this link above),
+             * and if so, copy in the data.
+             */
+            if (!linkScp->mountPointStringp[0]) {
+                strncpy(linkScp->mountPointStringp, bufp->datap, temp);
+                linkScp->mountPointStringp[temp] = 0;  /* null terminate */
             }
-        } /* while loop to get the data */
-                
-        /* now if we still have no link read in,
-         * copy the data from the buffer */
-        if ((temp = linkScp->length.LowPart) >= MOUNTPOINTLEN) {
             buf_Release(bufp);
-            return CM_ERROR_TOOBIG;
         }
+        
+        if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
+            linkScp->fileType = CM_SCACHETYPE_DFSLINK;
 
-        /* otherwise, it fits; make sure it is still null (could have
-         * lost race with someone else referencing this link above),
-         * and if so, copy in the data.
-         */
-        if (!linkScp->mountPointStringp[0]) {
-            strncpy(linkScp->mountPointStringp, bufp->datap, temp);
-            linkScp->mountPointStringp[temp] = 0;      /* null terminate */
-
-            if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
-                 linkScp->fileType = CM_SCACHETYPE_DFSLINK;
-        }
-        buf_Release(bufp);
     }  /* don't have sym link contents cached */
 
     return 0;
@@ -1752,12 +1810,19 @@ long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
         StringCchCatA(tsp->data,lengthof(tsp->data), "\\");
         StringCchCatA(tsp->data,lengthof(tsp->data), pathSuffixp);
     }
+
     if (code == 0) {
         clientchar_t * cpath = cm_FsStringToClientStringAlloc(tsp->data, -1, NULL);
+        if (cpath != NULL) {
         cm_ClientStrCpy(tsp->wdata, lengthof(tsp->wdata), cpath);
         free(cpath);
         *newSpaceBufferp = tsp;
     } else {
+            code = CM_ERROR_NOSUCHPATH;
+        }
+    } 
+
+    if (code != 0) {
         cm_FreeSpace(tsp);
 
         if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp) {
@@ -1803,10 +1868,12 @@ long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
     int fid_count = 0;          /* number of fids processed in this path walk */
     int i;
 
+    *outScpp = NULL;
+
 #ifdef DEBUG_REFCOUNT
     afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
     osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %S tidpath %S flags 0x%x",
-             rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
+             rootSCachep, pathp ? pathp : L"<NULL>", tidPathp ? tidPathp : L"<NULL>", 
              flags);
 #endif
 
@@ -1883,17 +1950,13 @@ long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
                         fid_count = i+1;
                     } else {
                         /* add the new fid to the list */
-                        for ( i=0; i<fid_count; i++) {
-                            if ( !cm_FidCmp(&nscp->fid, &fids[i]) ) {
-                                code = CM_ERROR_TOO_MANY_SYMLINKS;
-                                cm_ReleaseSCache(nscp);
-                                nscp = NULL;
-                                break;
-                            }
-                        }
-                        if (i == fid_count && fid_count < MAX_FID_COUNT) {
-                            fids[fid_count++] = nscp->fid;
-                        }
+                        if (fid_count == MAX_FID_COUNT) {
+                            code = CM_ERROR_TOO_MANY_SYMLINKS;
+                            cm_ReleaseSCache(nscp);
+                            nscp = NULL;
+                            break;
+                        }       
+                        fids[fid_count++] = nscp->fid;
                     }
                 }
 
@@ -1977,9 +2040,10 @@ long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
                     }
 
                     if (code == 0 && linkScp != NULL) {
-                        if (linkScp == cm_data.rootSCachep) 
+                        if (linkScp == cm_data.rootSCachep) {
                             fid_count = 0;
-                        else {
+                            i = 0;
+                        } else {
                             for ( i=0; i<fid_count; i++) {
                                 if ( !cm_FidCmp(&linkScp->fid, &fids[i]) ) {
                                     code = CM_ERROR_TOO_MANY_SYMLINKS;
@@ -2072,7 +2136,7 @@ long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
         cm_ReleaseSCache(tscp);
 
 #ifdef DEBUG_REFCOUNT
-    afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp)->refCount);
+    afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp) ? (*outScpp)->refCount : 0);
 #endif
     osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
     return code;
@@ -2100,6 +2164,8 @@ long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
     cm_space_t *spacep;
     cm_scache_t *newRootScp;
 
+    *outScpp = NULL;
+
     osi_Log1(afsd_logp, "Evaluating symlink scp 0x%p", linkScp);
 
     code = cm_AssembleLink(linkScp, "", &newRootScp, &spacep, userp, reqp);
@@ -2230,9 +2296,11 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
     long j;
     cm_scache_t *scp;
     cm_fid_t tfid;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     int inlinebulk = 0;                /* Did we use InlineBulkStatus RPC or not? */
         
+    memset(&volSync, 0, sizeof(volSync));
+
     /* otherwise, we may have one or more bulk stat's worth of stuff in bb;
      * make the calls to create the entries.  Handle AFSCBMAX files at a
      * time.
@@ -2255,9 +2323,9 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
             if (code) 
                 continue;
 
-            callp = cm_GetRxConn(connp);
+            rxconnp = cm_GetRxConn(connp);
            if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
-               code = RXAFS_InlineBulkStatus(callp, &fidStruct,
+               code = RXAFS_InlineBulkStatus(rxconnp, &fidStruct,
                                      &statStruct, &callbackStruct, &volSync);
                if (code == RXGEN_OPCODE) {
                    cm_SetServerNoInlineBulk(connp->serverp, 0);
@@ -2266,10 +2334,10 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
                }
            }
            if (!inlinebulk) {
-               code = RXAFS_BulkStatus(callp, &fidStruct,
+               code = RXAFS_BulkStatus(rxconnp, &fidStruct,
                                        &statStruct, &callbackStruct, &volSync);
            }
-            rx_PutConnection(callp);
+            rx_PutConnection(rxconnp);
 
         } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
                              &volSync, NULL, &cbReq, code));
@@ -2284,7 +2352,7 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
          * much better on the next immediate call, either.
          */
         if (code) {
-            cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+            cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
             break;
         }
 
@@ -2317,15 +2385,16 @@ cm_TryBulkStatRPC(cm_scache_t *dscp, cm_bulkStat_t *bbp, cm_user_t *userp, cm_re
                          | CM_SCACHEFLAG_SIZESTORING))) {
                 cm_EndCallbackGrantingCall(scp, &cbReq,
                                             &bbp->callbacks[j],
+                                            &volSync,
                                             CM_CALLBACK_MAINTAINCOUNT);
-                cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, 0);
+                cm_MergeStatus(dscp, scp, &bbp->stats[j], &volSync, userp, reqp, 0);
             }       
             lock_ReleaseWrite(&scp->rw);
             cm_ReleaseSCache(scp);
         } /* all files in the response */
         /* now tell it to drop the count,
          * after doing the vnode processing above */
-        cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+        cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
     }  /* while there are still more files to process */
 
     /* If we did the InlineBulk RPC pull out the return code and log it */
@@ -2526,7 +2595,9 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
     cm_conn_t *connp;
     AFSFid tfid;
     AFSStoreStatus afsInStatus;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
+
+    memset(&volSync, 0, sizeof(volSync));
 
     /* handle file length setting */
     if (attrp->mask & CM_ATTRMASK_LENGTH)
@@ -2556,10 +2627,10 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
         if (code) 
             continue;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_StoreStatus(callp, &tfid,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_StoreStatus(rxconnp, &tfid,
                                   &afsInStatus, &afsOutStatus, &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp,
                          &scp->fid, &volSync, NULL, NULL, code));
@@ -2573,7 +2644,7 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
     lock_ObtainWrite(&scp->rw);
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STORESTATUS);
     if (code == 0)
-        cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp,
+        cm_MergeStatus(NULL, scp, &afsOutStatus, &volSync, userp, reqp,
                         CM_MERGEFLAG_FORCE|CM_MERGEFLAG_STOREDATA);
        
     /* if we're changing the mode bits, discard the ACL cache, 
@@ -2601,10 +2672,12 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
     AFSFetchStatus newFileStatus;
     AFSCallBack newFileCallback;
     AFSVolSync volSync;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t dirop;
     fschar_t * fnamep = NULL;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
@@ -2655,12 +2728,12 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
         dirAFSFid.Vnode = dscp->fid.vnode;
         dirAFSFid.Unique = dscp->fid.unique;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_CreateFile(connp->callp, &dirAFSFid, fnamep,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_CreateFile(connp->rxconnp, &dirAFSFid, fnamep,
                                  &inStatus, &newAFSFid, &newFileStatus,
                                  &updatedDirStatus, &newFileCallback,
                                  &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp,
                          &dscp->fid, &volSync, NULL, &cbReq, code));
@@ -2678,7 +2751,7 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
     lock_ObtainWrite(&dscp->rw);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
@@ -2694,20 +2767,19 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
             lock_ObtainWrite(&scp->rw);
            scp->creator = userp;               /* remember who created it */
             if (!cm_HaveCallback(scp)) {
-                cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
-                               userp, 0);
                 cm_EndCallbackGrantingCall(scp, &cbReq,
-                                           &newFileCallback, 0);
+                                           &newFileCallback, &volSync, 0);
+                cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
+                               userp, reqp, 0);
                 didEnd = 1;     
             }       
             lock_ReleaseWrite(&scp->rw);
-            *scpp = scp;
         }
     }
 
     /* make sure we end things properly */
     if (!didEnd)
-        cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+        cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
 
     if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
         cm_DirCreateEntry(&dirop, fnamep, &newFid);
@@ -2720,6 +2792,12 @@ long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *a
     if (fnamep)
         free(fnamep);
 
+    if (scp) {
+        if (scpp)
+            *scpp = scp;
+        else
+            cm_ReleaseSCache(scp);
+    }
     return code;
 }       
 
@@ -2747,7 +2825,7 @@ long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 }
 
 long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
-                 cm_user_t *userp, cm_req_t *reqp)
+                cm_user_t *userp, cm_req_t *reqp, cm_scache_t **scpp)
 {
     cm_conn_t *connp;
     long code;
@@ -2762,10 +2840,12 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
     AFSFetchStatus newDirStatus;
     AFSCallBack newDirCallback;
     AFSVolSync volSync;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t dirop;
     fschar_t * fnamep = NULL;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
@@ -2815,12 +2895,12 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
         dirAFSFid.Vnode = dscp->fid.vnode;
         dirAFSFid.Unique = dscp->fid.unique;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_MakeDir(connp->callp, &dirAFSFid, fnamep,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_MakeDir(connp->rxconnp, &dirAFSFid, fnamep,
                               &inStatus, &newAFSFid, &newDirStatus,
                               &updatedDirStatus, &newDirCallback,
                               &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp,
                         &dscp->fid, &volSync, NULL, &cbReq, code));
@@ -2838,7 +2918,7 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
     lock_ObtainWrite(&dscp->rw);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
@@ -2853,20 +2933,19 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
         if (code == 0) {
             lock_ObtainWrite(&scp->rw);
             if (!cm_HaveCallback(scp)) {
-                cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
-                                userp, 0);
                 cm_EndCallbackGrantingCall(scp, &cbReq,
-                                            &newDirCallback, 0);
+                                            &newDirCallback, &volSync, 0);
+                cm_MergeStatus(dscp, scp, &newDirStatus, &volSync,
+                                userp, reqp, 0);
                 didEnd = 1;             
             }
             lock_ReleaseWrite(&scp->rw);
-            cm_ReleaseSCache(scp);
         }
     }
 
     /* make sure we end things properly */
     if (!didEnd)
-        cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
+        cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, NULL, 0);
 
     if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
         cm_DirCreateEntry(&dirop, fnamep, &newFid);
@@ -2878,6 +2957,13 @@ long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *
 
     free(fnamep);
 
+    if (scp) {
+        if (scpp)
+            *scpp = scp;
+        else
+            cm_ReleaseSCache(scp);
+    }
+
     /* and return error code */
     return code;
 }       
@@ -2892,10 +2978,12 @@ long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long fl
     AFSFetchStatus updatedDirStatus;
     AFSFetchStatus newLinkStatus;
     AFSVolSync volSync;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t dirop;
     fschar_t * fnamep = NULL;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     if (dscp->fid.cell != sscp->fid.cell ||
         dscp->fid.volume != sscp->fid.volume) {
         return CM_ERROR_CROSSDEVLINK;
@@ -2927,10 +3015,10 @@ long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long fl
         existingAFSFid.Vnode = sscp->fid.vnode;
         existingAFSFid.Unique = sscp->fid.unique;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_Link(callp, &dirAFSFid, fnamep, &existingAFSFid,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_Link(rxconnp, &dirAFSFid, fnamep, &existingAFSFid,
             &newLinkStatus, &updatedDirStatus, &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
         osi_Log1(afsd_logp,"  RXAFS_Link returns 0x%x", code);
 
     } while (cm_Analyze(connp, userp, reqp,
@@ -2950,7 +3038,7 @@ long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long fl
     lock_ObtainWrite(&dscp->rw);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
@@ -2964,6 +3052,13 @@ long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long fl
     }
     cm_EndDirOp(&dirop);
 
+    /* Update the linked object status */
+    if (code == 0) {
+        lock_ObtainWrite(&sscp->rw);
+        cm_MergeStatus(NULL, sscp, &newLinkStatus, &volSync, userp, reqp, 0);
+        lock_ReleaseWrite(&sscp->rw);
+    }
+
     free(fnamep);
 
     return code;
@@ -2982,10 +3077,12 @@ long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, lo
     AFSFetchStatus updatedDirStatus;
     AFSFetchStatus newLinkStatus;
     AFSVolSync volSync;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t dirop;
     fschar_t *fnamep = NULL;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     /* 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
      * call completes.
@@ -3015,11 +3112,11 @@ long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, lo
         dirAFSFid.Vnode = dscp->fid.vnode;
         dirAFSFid.Unique = dscp->fid.unique;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_Symlink(callp, &dirAFSFid, fnamep, contentsp,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_Symlink(rxconnp, &dirAFSFid, fnamep, contentsp,
                               &inStatus, &newAFSFid, &newLinkStatus,
                               &updatedDirStatus, &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp,
                          &dscp->fid, &volSync, NULL, NULL, code));
@@ -3037,7 +3134,7 @@ long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, lo
     lock_ObtainWrite(&dscp->rw);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
@@ -3065,7 +3162,7 @@ long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, lo
             lock_ObtainWrite(&scp->rw);
             if (!cm_HaveCallback(scp)) {
                 cm_MergeStatus(dscp, scp, &newLinkStatus, &volSync,
-                                userp, 0);
+                                userp, reqp, 0);
             }       
             lock_ReleaseWrite(&scp->rw);
             cm_ReleaseSCache(scp);
@@ -3105,11 +3202,13 @@ long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_
     int didEnd;
     AFSFetchStatus updatedDirStatus;
     AFSVolSync volSync;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t dirop;
     cm_scache_t *scp = NULL;
     int free_fnamep = FALSE;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     if (fnamep == NULL) {
         code = -1;
 #ifdef USE_BPLUS
@@ -3154,10 +3253,10 @@ long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_
         dirAFSFid.Vnode = dscp->fid.vnode;
         dirAFSFid.Unique = dscp->fid.unique;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_RemoveDir(callp, &dirAFSFid, fnamep,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_RemoveDir(rxconnp, &dirAFSFid, fnamep,
                                &updatedDirStatus, &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp,
                         &dscp->fid, &volSync, NULL, NULL, code));
@@ -3176,7 +3275,7 @@ long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
         cm_dnlcRemove(dscp, cnamep); 
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, reqp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
@@ -3262,13 +3361,52 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
     AFSFetchStatus updatedNewDirStatus;
     AFSVolSync volSync;
     int oneDir;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_dirOp_t oldDirOp;
     cm_fid_t   fileFid;
     int        diropCode = -1;
     cm_dirOp_t newDirOp;
     fschar_t * newNamep = NULL;
     int free_oldNamep = FALSE;
+    cm_scache_t *oldScp = NULL, *newScp = NULL;
+
+    memset(&volSync, 0, sizeof(volSync));
+
+    if (cOldNamep == NULL || cNewNamep == NULL ||
+        cm_ClientStrLen(cOldNamep) == 0 ||
+        cm_ClientStrLen(cNewNamep) == 0)
+        return CM_ERROR_INVAL;
+
+    /* 
+     * Before we permit the operation, make sure that we do not already have
+     * an object in the destination directory that has a case-insensitive match
+     * for this name UNLESS the matching object is the object we are renaming.
+     */
+    code = cm_Lookup(oldDscp, cOldNamep, 0, userp, reqp, &oldScp);
+    if (code) {
+        osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S old name lookup failed", 
+                 oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
+        goto done;
+    }
+
+    code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &newScp);
+    if (code == 0) {
+        /* found a matching object with the new name */
+        if (cm_FidCmp(&oldScp->fid, &newScp->fid)) {
+            /* and they don't match so return an error */
+            osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists", 
+                      newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
+            code = CM_ERROR_EXISTS;
+        }
+        cm_ReleaseSCache(newScp);
+        newScp = NULL;
+    } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
+        code = CM_ERROR_EXISTS;
+    } else {
+        code = 0;
+    }
+    if (code) 
+        goto done;
 
     if (oldNamep == NULL) {
         code = -1;
@@ -3281,8 +3419,11 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
             cm_EndDirOp(&oldDirOp);
         }
 #endif
-        if (code)
+        if (code) {
+            osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S Original Name lookup failed", 
+                      oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
             goto done;
+        }
     }
 
 
@@ -3294,6 +3435,8 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
     if (oldDscp == newDscp) {
         /* check for identical names */
         if (cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
+            osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_RENAME_IDENTICAL", 
+                      oldDscp, newDscp);
             code = CM_ERROR_RENAME_IDENTICAL;
             goto done;
         }
@@ -3315,6 +3458,8 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
         oneDir = 0;
         if (oldDscp->fid.cell != newDscp->fid.cell ||
              oldDscp->fid.volume != newDscp->fid.volume) {
+            osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p CM_ERROR_CROSSDEVLINK", 
+                      oldDscp, newDscp);
             code = CM_ERROR_CROSSDEVLINK;
             goto done;
         }
@@ -3324,6 +3469,8 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
          * stale info.  Avoid deadlocks and quit now.
          */
         if (oldDscp->fid.vnode == newDscp->fid.vnode) {
+            osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p newDscp 0x%p vnode collision", 
+                      oldDscp, newDscp);
             code = CM_ERROR_CROSSDEVLINK;
             goto done;
         }
@@ -3409,12 +3556,12 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
         newDirAFSFid.Vnode = newDscp->fid.vnode;
         newDirAFSFid.Unique = newDscp->fid.unique;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_Rename(rxconnp, &oldDirAFSFid, oldNamep,
                             &newDirAFSFid, newNamep,
                             &updatedOldDirStatus, &updatedNewDirStatus,
                             &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
                          &volSync, NULL, NULL, code));
@@ -3435,34 +3582,31 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
 
     if (code == 0)
         cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
-                       userp, CM_MERGEFLAG_DIROP);
+                       userp, reqp, CM_MERGEFLAG_DIROP);
     lock_ReleaseWrite(&oldDscp->rw);
 
-    if (code == 0) {
-        if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
-
+    if (code == 0 && cm_CheckDirOpForSingleChange(&oldDirOp)) {
 #ifdef USE_BPLUS
-            diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
-            if (diropCode == CM_ERROR_INEXACT_MATCH)
-                diropCode = 0;
-            else if (diropCode == EINVAL)
+        diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
+        if (diropCode == CM_ERROR_INEXACT_MATCH)
+            diropCode = 0;
+        else if (diropCode == EINVAL)
 #endif
-                diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
+            diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
 
-            if (diropCode == 0) {
-                if (oneDir) {
-                    diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
-#ifdef USE_BPLUS
-                    cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
+        if (diropCode == 0) {
+            if (oneDir) {
+                diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS        
+                cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
 #endif
-                }
+            }
                 
-                if (diropCode == 0) { 
-                    diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+            if (diropCode == 0) { 
+                diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
 #ifdef USE_BPLUS
-                    cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
-#endif
-                }
+                cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+#endif  
             }
         }
     }
@@ -3478,9 +3622,20 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
         cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
         if (code == 0)
             cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
-                            userp, CM_MERGEFLAG_DIROP);
+                            userp, reqp, CM_MERGEFLAG_DIROP);
         lock_ReleaseWrite(&newDscp->rw);
 
+#if 0 
+        /* 
+         * The following optimization does not work.  
+         * When the file server processed a RXAFS_Rename() request the 
+         * FID of the object being moved between directories is not 
+         * preserved.  The client does not know the new FID nor the 
+         * version number of the target.  Not only can we not create
+         * the directory entry in the new directory, but we can't 
+         * preserve the cached data for the file.  It must be re-read
+         * from the file server.  - jaltman, 2009/02/20
+         */
         if (code == 0) {
             /* we only make the local change if we successfully made
                the change in the old directory AND there was only one
@@ -3492,10 +3647,23 @@ long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep
 #endif
             }
         }
+#endif /* 0 */
         cm_EndDirOp(&newDirOp);
     }
 
+    /* 
+     * After the rename the file server has invalidated the callbacks
+     * on the file that was moved nor do we have a directory reference 
+     * to it anymore.
+     */
+    lock_ObtainWrite(&oldScp->rw);
+    cm_DiscardSCache(oldScp);
+    lock_ReleaseWrite(&oldScp->rw);
+
   done:
+    if (oldScp)
+        cm_ReleaseSCache(oldScp);
+
     if (free_oldNamep)
         free(oldNamep);
 
@@ -3876,7 +4044,7 @@ long cm_LockCheckRead(cm_scache_t *scp,
 
         if (INTERSECT_RANGE(range, fileLock->range)) {
             if (IS_LOCK_ACTIVE(fileLock)) {
-                if (fileLock->key == key) {
+                if (cm_KeyEquals(&fileLock->key, &key, 0)) {
 
                     /* If there is an active lock for this client, it
                        is safe to substract ranges.*/
@@ -3898,7 +4066,7 @@ long cm_LockCheckRead(cm_scache_t *scp,
                         cm_LockRangeSubtract(&range, &fileLock->range);
                 }
             } else if (IS_LOCK_LOST(fileLock) &&
-                      (fileLock->key == key || fileLock->lockType == LockWrite)) {
+                       (cm_KeyEquals(&fileLock->key, &key, 0) || fileLock->lockType == LockWrite)) {
                 code = CM_ERROR_BADFD;
                 break;
             }
@@ -3957,7 +4125,7 @@ long cm_LockCheckWrite(cm_scache_t *scp,
 
         if (INTERSECT_RANGE(range, fileLock->range)) {
             if (IS_LOCK_ACTIVE(fileLock)) {
-                if (fileLock->key == key) {
+                if (cm_KeyEquals(&fileLock->key, &key, 0)) {
                     if (fileLock->lockType == LockWrite) {
 
                         /* if there is an active lock for this client, it
@@ -4022,10 +4190,12 @@ long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
     AFSFid tfid;
     cm_fid_t cfid;
     cm_conn_t * connp;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     AFSVolSync volSync;
     afs_uint32 reqflags = reqp->flags;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     tfid.Volume = scp->fid.volume;
     tfid.Vnode = scp->fid.vnode;
     tfid.Unique = scp->fid.unique;
@@ -4041,10 +4211,10 @@ long cm_IntSetLock(cm_scache_t * scp, cm_user_t * userp, int lockType,
         if (code) 
             break;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_SetLock(callp, &tfid, lockType,
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_SetLock(rxconnp, &tfid, lockType,
                              &volSync);
-        rx_PutConnection(callp);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
                         NULL, NULL, code));
@@ -4068,9 +4238,11 @@ long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
     AFSFid tfid;
     cm_fid_t cfid;
     cm_conn_t * connp;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     AFSVolSync volSync;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     tfid.Volume = scp->fid.volume;
     tfid.Vnode = scp->fid.vnode;
     tfid.Unique = scp->fid.unique;
@@ -4085,9 +4257,9 @@ long cm_IntReleaseLock(cm_scache_t * scp, cm_user_t * userp,
         if (code) 
             break;
 
-        callp = cm_GetRxConn(connp);
-        code = RXAFS_ReleaseLock(callp, &tfid, &volSync);
-        rx_PutConnection(callp);
+        rxconnp = cm_GetRxConn(connp);
+        code = RXAFS_ReleaseLock(rxconnp, &tfid, &volSync);
+        rx_PutConnection(rxconnp);
 
     } while (cm_Analyze(connp, userp, reqp, &cfid, &volSync,
                         NULL, NULL, code));
@@ -4207,8 +4379,8 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
 
     osi_Log4(afsd_logp, "cm_Lock scp 0x%x type 0x%x offset %d length %d",
              scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
-    osi_Log3(afsd_logp, "... allowWait %d key 0x%x:%x", allowWait, 
-             (unsigned long)(key >> 32), (unsigned long)(key & 0xffffffff));
+    osi_Log4(afsd_logp, "... allowWait %d key <0x%x, 0x%x, 0x%x>", allowWait, 
+             key.process_id, key.session_id, key.file_id);
 
     /*
    A client C can OBTAIN a lock L on cm_scache_t S iff (both 3 and 4):
@@ -4242,7 +4414,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
             (cm_file_lock_t *)((char *) q - offsetof(cm_file_lock_t, fileq));
 
         if (IS_LOCK_LOST(fileLock)) {
-            if (fileLock->key == key) {
+            if (cm_KeyEquals(&fileLock->key, &key, 0)) {
                 code = CM_ERROR_BADFD;
                 break;
             } else if (fileLock->lockType == LockWrite && INTERSECT_RANGE(range, fileLock->range)) {
@@ -4552,11 +4724,13 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
                  "cm_Lock Rejecting lock (code = 0x%x)", code);
     }
 
+    /* Convert from would block to lock not granted */
+    if (code == CM_ERROR_WOULDBLOCK)
+        code = CM_ERROR_LOCK_NOT_GRANTED;
+
     return code;
 }
 
-static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags);
-
 /* Called with scp->rw held */
 long cm_UnlockByKey(cm_scache_t * scp,
                    cm_key_t key,
@@ -4569,11 +4743,9 @@ long cm_UnlockByKey(cm_scache_t * scp,
     osi_queue_t *q, *qn;
     int n_unlocks = 0;
 
-    osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x flags=0x%x",
-             scp,
-             (unsigned long)(key >> 32),
-             (unsigned long)(key & 0xffffffff),
-             flags);
+    osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key <0x%x,0x%x,0x%x",
+             scp, key.process_id, key.session_id, key.file_id);
+    osi_Log1(afsd_logp, "    flags=0x%x", flags);
 
     lock_ObtainWrite(&cm_scacheLock);
 
@@ -4589,9 +4761,8 @@ long cm_UnlockByKey(cm_scache_t * scp,
                  (unsigned long) fileLock->range.offset,
                  (unsigned long) fileLock->range.length,
                 fileLock->lockType);
-        osi_Log3(afsd_logp, "     key[0x%x:%x] flags[0x%x]",
-                 (unsigned long)(fileLock->key >> 32),
-                 (unsigned long)(fileLock->key & 0xffffffff),
+        osi_Log4(afsd_logp, "     key<0x%x, 0x%x, 0x%x> flags[0x%x]",
+                 fileLock->key.process_id, fileLock->key.session_id, fileLock->key.file_id,
                  fileLock->flags);
 
         if (cm_FidCmp(&fileLock->fid, &fileLock->scp->fid)) {
@@ -4611,7 +4782,7 @@ long cm_UnlockByKey(cm_scache_t * scp,
 #endif
 
         if (!IS_LOCK_DELETED(fileLock) &&
-            cm_KeyEquals(fileLock->key, key, flags)) {
+            cm_KeyEquals(&fileLock->key, &key, flags)) {
             osi_Log3(afsd_logp, "...Unlock range [%d,+%d] type %d",
                     fileLock->range.offset,
                     fileLock->range.length,
@@ -4748,6 +4919,7 @@ long cm_Unlock(cm_scache_t *scp,
                unsigned char sLockType,
                LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
                cm_key_t key, 
+               afs_uint32 flags,
                cm_user_t *userp, 
                cm_req_t *reqp)
 {
@@ -4756,12 +4928,19 @@ long cm_Unlock(cm_scache_t *scp,
     cm_file_lock_t *fileLock;
     osi_queue_t *q;
     int release_userp = FALSE;
+    int exact_match = !(flags & CM_UNLOCK_FLAG_MATCH_RANGE);
+    int lock_found  = 0;
+    LARGE_INTEGER RangeEnd;
 
     osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
              scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
-    osi_Log2(afsd_logp, "... key 0x%x:%x",
-             (unsigned long) (key >> 32), (unsigned long) (key & 0xffffffff));
+    osi_Log4(afsd_logp, "... key <0x%x,0x%x,0x%x> flags 0x%x",
+             key.process_id, key.session_id, key.file_id, flags);
+
+    if (!exact_match)
+        RangeEnd.QuadPart = LOffset.QuadPart + LLength.QuadPart;
 
+  try_again:
     lock_ObtainRead(&cm_scacheLock);
 
     for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
@@ -4784,21 +4963,39 @@ long cm_Unlock(cm_scache_t *scp,
             osi_assertx(FALSE, "invalid fid value");
         }
 #endif
-        if (!IS_LOCK_DELETED(fileLock) &&
-            fileLock->key == key &&
-            fileLock->range.offset == LOffset.QuadPart &&
-            fileLock->range.length == LLength.QuadPart) {
-            break;
+        if (exact_match) {
+            if (!IS_LOCK_DELETED(fileLock) &&
+                 cm_KeyEquals(&fileLock->key, &key, 0) &&
+                 fileLock->range.offset == LOffset.QuadPart &&
+                 fileLock->range.length == LLength.QuadPart) {
+                lock_found = 1;
+                break;
+            }
+        } else {
+
+            if (!IS_LOCK_DELETED(fileLock) &&
+                 cm_KeyEquals(&fileLock->key, &key, 0) &&
+                 fileLock->range.offset >= LOffset.QuadPart &&
+                 fileLock->range.offset < RangeEnd.QuadPart &&
+                 (fileLock->range.offset + fileLock->range.length) <= RangeEnd.QuadPart) {
+                lock_found = 1;
+                break;
+            }
         }
     }
 
     if (!q) {
-        osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
-        
         lock_ReleaseRead(&cm_scacheLock);
 
-        /* The lock didn't exist anyway. *shrug* */
-        return CM_ERROR_RANGE_NOT_LOCKED;
+        if (lock_found && !exact_match) {
+            code = 0;
+            goto done;
+        } else {
+            osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
+        
+            /* The lock didn't exist anyway. *shrug* */
+            return CM_ERROR_RANGE_NOT_LOCKED;
+        }
     }
 
     /* discard lock record */
@@ -4923,8 +5120,13 @@ long cm_Unlock(cm_scache_t *scp,
         }
     }
 
-    if (release_userp)
+    if (release_userp) {
         cm_ReleaseUser(userp);
+        release_userp = FALSE;
+    }
+
+    if (!exact_match)
+        goto try_again;         /* might be more than one lock in the range */
 
  done:
 
@@ -4963,7 +5165,7 @@ void cm_LockMarkSCacheLost(cm_scache_t * scp)
     }
 
     scp->serverLock = -1;
-    scp->lockDataVersion = -1;
+    scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
     lock_ReleaseWrite(&cm_scacheLock);
 }
 
@@ -4977,9 +5179,11 @@ void cm_CheckLocks()
     AFSVolSync volSync;
     cm_conn_t *connp;
     long code;
-    struct rx_connection * callp;
+    struct rx_connection * rxconnp;
     cm_scache_t * scp;
 
+    memset(&volSync, 0, sizeof(volSync));
+
     cm_InitReq(&req);
 
     lock_ObtainWrite(&cm_scacheLock);
@@ -5079,10 +5283,10 @@ void cm_CheckLocks()
                         if (code) 
                             break;
 
-                        callp = cm_GetRxConn(connp);
-                        code = RXAFS_ExtendLock(callp, &tfid,
+                        rxconnp = cm_GetRxConn(connp);
+                        code = RXAFS_ExtendLock(rxconnp, &tfid,
                                                 &volSync);
-                        rx_PutConnection(callp);
+                        rx_PutConnection(rxconnp);
 
                         osi_Log1(afsd_logp, "   ExtendLock returns %d", code);
 
@@ -5207,9 +5411,8 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
              (unsigned)(oldFileLock->range.offset & 0xffffffff),
              (unsigned)(oldFileLock->range.length >> 32),
              (unsigned)(oldFileLock->range.length & 0xffffffff));
-    osi_Log3(afsd_logp, "    key(%x:%x) flags=%x",
-             (unsigned)(oldFileLock->key >> 32),
-             (unsigned)(oldFileLock->key & 0xffffffff),
+    osi_Log4(afsd_logp, "    key<0x%x,0x%x,0x%x> flags=%x",
+             oldFileLock->key.process_id, oldFileLock->key.session_id, oldFileLock->key.file_id,
              (unsigned)(oldFileLock->flags));
 
     /* if the lock has already been granted, then we have nothing to do */
@@ -5281,7 +5484,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
                 ((char *) q - offsetof(cm_file_lock_t, fileq));
 
             if (IS_LOCK_LOST(fileLock)) {
-                if (fileLock->key == oldFileLock->key) {
+                if (cm_KeyEquals(&fileLock->key, &oldFileLock->key, 0)) {
                     code = CM_ERROR_BADFD;
                     oldFileLock->flags |= CM_FILELOCK_FLAG_LOST;
                     osi_Log1(afsd_logp, "    found lost lock %p for same key.  Marking lock as lost",
@@ -5483,27 +5686,21 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
     return code;
 }
 
-cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int file_id)
+cm_key_t cm_GenerateKey(afs_uint16 session_id, afs_offs_t process_id, afs_uint16 file_id)
 {
-#ifdef DEBUG
-    osi_assertx((process_id & 0xffffffff) == process_id, "unexpected process_id");
-    osi_assertx((session_id & 0xffff) == session_id, "unexpected session_id");
-    osi_assertx((file_id & 0xffff) == file_id, "unexpected file_id");
-#endif
+    cm_key_t key;
 
-    return 
-        (((cm_key_t) (process_id & 0xffffffff)) << 32) |
-        (((cm_key_t) (session_id & 0xffff)) << 16) |
-        (((cm_key_t) (file_id & 0xffff)));
+    key.process_id = process_id;
+    key.session_id = session_id;
+    key.file_id = file_id;
+
+    return key;
 }
 
-static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags)
+int cm_KeyEquals(cm_key_t *k1, cm_key_t *k2, int flags)
 {
-    if (flags & CM_UNLOCK_BY_FID) {
-        return ((k1 & 0xffffffff) == (k2 & 0xffffffff));
-    } else {
-        return (k1 == k2);
-    }
+    return (k1->session_id == k2->session_id) && (k1->file_id == k2->file_id) &&
+        ((flags & CM_UNLOCK_BY_FID) || (k1->process_id == k2->process_id));
 }
 
 void cm_ReleaseAllLocks(void)