windows-checkntopen-20080223
[openafs.git] / src / WINNT / afsd / cm_vnodeops.c
index 512bc03..f8879f9 100644 (file)
@@ -400,7 +400,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 _done;
+               goto _syncopdone;
            }
 
            (*ldpp)->key = key;
@@ -434,17 +434,20 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         goto _done;
     }
 
+  _syncopdone:
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
 
  _done:
     lock_ReleaseMutex(&scp->mx);
 
+    osi_Log3(afsd_logp,"cm_CheckNTOpen scp 0x%p ldp 0x%p code 0x%x", scp, *ldpp, code);
     return code;
 }
 
 extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, 
                               cm_lock_data_t ** ldpp)
 {
+    osi_Log2(afsd_logp,"cm_CheckNTOpenDone scp 0x%p ldp 0x%p", scp, *ldpp);
     if (*ldpp) {
        lock_ObtainMutex(&scp->mx);
        cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength, 
@@ -474,7 +477,7 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
     long code;
     osi_hyper_t thyper;
     cm_buf_t *bufferp;
-    cm_dirEntry_t *dep;
+    cm_dirEntry_t *dep = 0;
     unsigned short *hashTable;
     unsigned int i, idx;
     int BeyondPage = 0, HaveDot = 0, HaveDotDot = 0;
@@ -494,9 +497,7 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
         return code;
 
     thyper.HighPart = 0; thyper.LowPart = 0;
-    lock_ObtainRead(&scp->bufCreateLock);
     code = buf_Get(scp, &thyper, &bufferp);
-    lock_ReleaseRead(&scp->bufCreateLock);
     if (code)
         return code;
 
@@ -573,7 +574,7 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
 {
     char *tp;
     long code;
-    cm_dirEntry_t *dep;
+    cm_dirEntry_t *dep = 0;
     cm_buf_t *bufferp;
     long temp;
     osi_hyper_t dirLength;
@@ -730,9 +731,7 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
                 bufferp = NULL;
             }
 
-            lock_ObtainRead(&scp->bufCreateLock);
             code = buf_Get(scp, &thyper, &bufferp);
-            lock_ReleaseRead(&scp->bufCreateLock);
             if (code) {
                 /* if buf_Get() fails we do not have a buffer object to lock */
                 bufferp = NULL;
@@ -975,10 +974,8 @@ long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     /* otherwise, we have to read it in */
     lock_ReleaseMutex(&scp->mx);
 
-    lock_ObtainRead(&scp->bufCreateLock);
     thyper.LowPart = thyper.HighPart = 0;
     code = buf_Get(scp, &thyper, &bufp);
-    lock_ReleaseRead(&scp->bufCreateLock);
 
     lock_ObtainMutex(&scp->mx);
     if (code)
@@ -1084,7 +1081,7 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
         /* normal mt pt */
         strcpy(volNamep, mpNamep+1);
 
-        cellp = cm_FindCellByID(scp->fid.cell);
+        cellp = cm_FindCellByID(scp->fid.cell, 0);
     }
 
     if (!cellp) {
@@ -1121,6 +1118,8 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
     lock_ObtainMutex(&scp->mx);
         
     if (code == 0) {
+        afs_uint32 cell, volume;
+
         /* save the parent of the volume root for this is the 
          * place where the volume is mounted and we must remember 
          * this in the volume structure rather than just in the 
@@ -1131,16 +1130,18 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
         volp->dotdotFid = dscp->fid;
         lock_ReleaseMutex(&volp->mx);
 
-        scp->mountRootFid.cell = cellp->cellID;
+        cell = cellp->cellID;
         
         /* if the mt pt originates in a .backup volume (not a .readonly)
          * and FollowBackupPath is active, and if there is a .backup
          * volume for the target, then use the .backup of the target
          * instead of the read-write.
          */
-        if (cm_followBackupPath && targetType == RWVOL &&
-            (scp->flags & CM_SCACHEFLAG_RO|CM_SCACHEFLAG_PURERO) == CM_SCACHEFLAG_RO &&
-            volp->bk.ID != 0) {
+        if (cm_followBackupPath && 
+            volp->bk.ID != 0 &&
+            (dscp->flags & (CM_SCACHEFLAG_RO|CM_SCACHEFLAG_PURERO)) == CM_SCACHEFLAG_RO &&
+            (targetType == RWVOL || targetType == ROVOL && volp->ro.ID == 0)
+            ) {
             targetType = BACKVOL;
         } 
         /* if the mt pt is in a read-only volume (not just a
@@ -1154,15 +1155,14 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
             targetType = ROVOL;
         }
         if (targetType == ROVOL)
-            scp->mountRootFid.volume = volp->ro.ID;
+            volume = volp->ro.ID;
         else if (targetType == BACKVOL)
-            scp->mountRootFid.volume = volp->bk.ID;
+            volume = volp->bk.ID;
         else
-            scp->mountRootFid.volume = volp->rw.ID;
+            volume = volp->rw.ID;
 
         /* the rest of the fid is a magic number */
-        scp->mountRootFid.vnode = 1;
-        scp->mountRootFid.unique = 1;
+        cm_SetFid(&scp->mountRootFid, cell, volume, 1, 1);
         scp->mountRootGen = cm_data.mountRootGen;
 
         tfid = scp->mountRootFid;
@@ -1280,27 +1280,43 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
             else
                 return CM_ERROR_NOSUCHFILE;
         }
-        else {  /* nonexistent dir on freelance root, so add it */
+        else if (!strchr(namep, '#') && !strchr(namep, '%') &&
+                 strcmp(namep, "srvsvc") && strcmp(namep, "wkssvc") &&
+                 strcmp(namep, "ipc$")) {
+            /* nonexistent dir on freelance root, so add it */
             char fullname[200] = ".";
             int  found = 0;
 
             osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
                       osi_LogSaveString(afsd_logp,namep));
+
+            /* 
+             * There is an ugly behavior where a share name "foo" will be searched
+             * for as "fo".  If the searched for name differs by an already existing
+             * symlink or mount point in the Freelance directory, do not add the 
+             * new value automatically.
+             */
+
+            code = -1;
             if (namep[0] == '.') {
                 if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
                     found = 1;
-                    if ( stricmp(&namep[1], &fullname[1]) )
+                    if (!cm_FreelanceMountPointExists(fullname, 0))
+                        code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
+                    if ( stricmp(&namep[1], &fullname[1]) && 
+                                               !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+                                               !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
-                    else
-                        code = cm_FreelanceAddMount(namep, &fullname[1], "root.cell.", 1, &rock.fid);
                 }
             } else {
                 if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
                     found = 1;
-                    if ( stricmp(namep, fullname) )
+                    if (!cm_FreelanceMountPointExists(fullname, 0))
+                        code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
+                    if ( stricmp(namep, fullname) && 
+                                               !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+                                               !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
                         code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
-                    else
-                        code = cm_FreelanceAddMount(namep, fullname, "root.cell.", 0, &rock.fid);
                 }
             }
             if (!found || code < 0) {   /* add mount point failed, so give up */
@@ -1411,6 +1427,7 @@ long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
     cm_cell_t *   cellp = NULL;
     cm_volume_t * volp = NULL;
     cm_fid_t      fid;
+    afs_uint32    volume;
     int           volType;
     int           mountType = RWVOL;
 
@@ -1477,18 +1494,15 @@ long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
     if (code != 0)
         goto _exit_cleanup;
 
-    fid.cell = cellp->cellID;
-
     if (volType == BACKVOL)
-        fid.volume = volp->bk.ID;
+        volume = volp->bk.ID;
     else if (volType == ROVOL ||
              (volType == RWVOL && mountType == ROVOL && volp->ro.ID != 0))
-        fid.volume = volp->ro.ID;
+        volume = volp->ro.ID;
     else
-        fid.volume = volp->rw.ID;
+        volume = volp->rw.ID;
 
-    fid.vnode = 1;
-    fid.unique = 1;
+    cm_SetFid(&fid, cellp->cellID, volume, 1, 1);
 
     code = cm_GetSCache(&fid, outpScpp, userp, reqp);
 
@@ -1644,7 +1658,7 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
     cm_dnlcRemove(dscp, namep);
     cm_SyncOpDone(dscp, NULL, sflags);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0);
+        cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 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 
@@ -1717,6 +1731,9 @@ long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
         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 */
@@ -1739,9 +1756,12 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
     char *linkp;
     cm_space_t *tsp;
 
+    *newRootScpp = NULL;
+    *newSpaceBufferp = NULL;
+
     lock_ObtainMutex(&linkScp->mx);
     code = cm_HandleLink(linkScp, userp, reqp);
-    if (code) 
+    if (code)
         goto done;
 
     /* if we may overflow the buffer, bail out; buffer is signficantly
@@ -1778,13 +1798,12 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
         } else {
             linkScp->fileType = CM_SCACHETYPE_DFSLINK;
             strcpy(tsp->data, linkp);
-            *newRootScpp = NULL;
             code = CM_ERROR_PATH_NOT_COVERED;
         }
-    } else if ( !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
+    } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
+                !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
         linkScp->fileType = CM_SCACHETYPE_DFSLINK;
         strcpy(tsp->data, linkp);
-        *newRootScpp = NULL;
         code = CM_ERROR_PATH_NOT_COVERED;
     } else if (*linkp == '\\' || *linkp == '/') {
 #if 0   
@@ -1800,19 +1819,24 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
          */
         linkScp->fileType = CM_SCACHETYPE_INVALID;
         strcpy(tsp->data, linkp);
-        *newRootScpp = NULL;
         code = CM_ERROR_NOSUCHPATH;
 #endif  
     } else {
         /* a relative link */
         strcpy(tsp->data, linkp);
-        *newRootScpp = NULL;
     }
     if (pathSuffixp[0] != 0) { /* if suffix string is non-null */
         strcat(tsp->data, "\\");
         strcat(tsp->data, pathSuffixp);
     }
-    *newSpaceBufferp = tsp;
+    if (code == 0)
+        *newSpaceBufferp = tsp;
+    else {
+        cm_FreeSpace(tsp);
+
+        if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp)
+            cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
+    }
 
   done:
     lock_ReleaseMutex(&linkScp->mx);
@@ -1925,6 +1949,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                             if (!cm_FidCmp(&nscp->fid, &fids[i]))
                                 break;
                         }
+                        fid_count = i+1;
                     } else {
                         /* add the new fid to the list */
                         for ( i=0; i<fid_count; i++) {
@@ -2228,10 +2253,7 @@ long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
     if (strcmp(dep->name, ".") == 0 || strcmp(dep->name, "..") == 0)
         return 0;
 
-    tfid.cell = scp->fid.cell;
-    tfid.volume = scp->fid.volume;
-    tfid.vnode = ntohl(dep->fid.vnode);
-    tfid.unique = ntohl(dep->fid.unique);
+    cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
     tscp = cm_FindSCache(&tfid);
     if (tscp) {
         if (lock_TryMutex(&tscp->mx)) {
@@ -2373,10 +2395,7 @@ cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
         /* otherwise, we should do the merges */
         for (i = 0; i<filesThisCall; i++) {
             j = filex + i;
-            tfid.cell = dscp->fid.cell;
-            tfid.volume = bb.fids[j].Volume;
-            tfid.vnode = bb.fids[j].Vnode;
-            tfid.unique = bb.fids[j].Unique;
+            cm_SetFid(&tfid, dscp->fid.cell, bb.fids[j].Volume, bb.fids[j].Vnode, bb.fids[j].Unique);
             code = cm_GetSCache(&tfid, &scp, userp, reqp);
             if (code != 0) 
                 continue;
@@ -2660,6 +2679,16 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
         return CM_ERROR_ATSYS;
     }
 
+#ifdef AFS_FREELANCE_CLIENT
+    /* Freelance root volume does not hold files */
+    if (cm_freelanceEnabled &&
+        dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+        dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+    {
+        return CM_ERROR_NOACCESS;
+    }
+#endif /* AFS_FREELANCE_CLIENT */
+
     /* before starting the RPC, mark that we're changing the file data, so
      * that someone who does a chmod will know to wait until our call
      * completes.
@@ -2714,7 +2743,7 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
     lock_ObtainMutex(&dscp->mx);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseMutex(&dscp->mx);
 
@@ -2724,10 +2753,7 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
      * info.
      */
     if (code == 0) {
-        newFid.cell = dscp->fid.cell;
-        newFid.volume = dscp->fid.volume;
-        newFid.vnode = newAFSFid.Vnode;
-        newFid.unique = newAFSFid.Unique;
+        cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
         code = cm_GetSCache(&newFid, &scp, userp, reqp);
         if (code == 0) {
             lock_ObtainMutex(&scp->mx);
@@ -2763,9 +2789,7 @@ long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 {
     long code;
 
-    lock_ObtainWrite(&scp->bufCreateLock);
     code = buf_CleanVnode(scp, userp, reqp);
-    lock_ReleaseWrite(&scp->bufCreateLock);
     if (code == 0) {
         lock_ObtainMutex(&scp->mx);
 
@@ -2810,6 +2834,16 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
         return CM_ERROR_ATSYS;
     }
 
+#ifdef AFS_FREELANCE_CLIENT
+    /* Freelance root volume does not hold subdirectories */
+    if (cm_freelanceEnabled &&
+        dscp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+        dscp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+    {
+        return CM_ERROR_NOACCESS;
+    }
+#endif /* AFS_FREELANCE_CLIENT */
+
     /* 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.
@@ -2864,7 +2898,7 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
     lock_ObtainMutex(&dscp->mx);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseMutex(&dscp->mx);
 
@@ -2874,10 +2908,7 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
      * info.
      */
     if (code == 0) {
-        newFid.cell = dscp->fid.cell;
-        newFid.volume = dscp->fid.volume;
-        newFid.vnode = newAFSFid.Vnode;
-        newFid.unique = newAFSFid.Unique;
+        cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
         code = cm_GetSCache(&newFid, &scp, userp, reqp);
         if (code == 0) {
             lock_ObtainMutex(&scp->mx);
@@ -2974,7 +3005,7 @@ long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
     lock_ObtainMutex(&dscp->mx);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseMutex(&dscp->mx);
 
@@ -3056,16 +3087,13 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
     lock_ObtainMutex(&dscp->mx);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseMutex(&dscp->mx);
 
     if (code == 0) {
         if (cm_CheckDirOpForSingleChange(&dirop)) {
-            newFid.cell = dscp->fid.cell;
-            newFid.volume = dscp->fid.volume;
-            newFid.vnode = newAFSFid.Vnode;
-            newFid.unique = newAFSFid.Unique;
+            cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
 
             cm_DirCreateEntry(&dirop, namep, &newFid);
 #ifdef USE_BPLUS
@@ -3081,10 +3109,7 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
      * info.
      */
     if (code == 0) {
-        newFid.cell = dscp->fid.cell;
-        newFid.volume = dscp->fid.volume;
-        newFid.vnode = newAFSFid.Vnode;
-        newFid.unique = newAFSFid.Unique;
+        cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
         code = cm_GetSCache(&newFid, &scp, userp, reqp);
         if (code == 0) {
             lock_ObtainMutex(&scp->mx);
@@ -3160,7 +3185,7 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
         cm_dnlcRemove(dscp, namep); 
-        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
+        cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseMutex(&dscp->mx);
 
@@ -3355,7 +3380,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
 
     if (code == 0)
         cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
-                        userp, 0);
+                        userp, CM_MERGEFLAG_DIROP);
     lock_ReleaseMutex(&oldDscp->mx);
 
     if (code == 0) {
@@ -3398,7 +3423,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
         cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
         if (code == 0)
             cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
-                            userp, 0);
+                            userp, CM_MERGEFLAG_DIROP);
         lock_ReleaseMutex(&newDscp->mx);
 
         if (code == 0) {
@@ -3906,9 +3931,6 @@ long cm_LockCheckWrite(cm_scache_t *scp,
 #endif
 }
 
-/* Forward dcl. */
-static void cm_LockMarkSCacheLost(cm_scache_t * scp);
-
 /* Called with cm_scacheLock write locked */
 static cm_file_lock_t * cm_GetFileLock(void) {
     cm_file_lock_t * l;
@@ -4713,7 +4735,7 @@ long cm_Unlock(cm_scache_t *scp,
         lock_ReleaseRead(&cm_scacheLock);
 
         /* The lock didn't exist anyway. *shrug* */
-        return 0;
+        return CM_ERROR_RANGE_NOT_LOCKED;
     }
 
     lock_ReleaseRead(&cm_scacheLock);
@@ -4854,7 +4876,7 @@ long cm_Unlock(cm_scache_t *scp,
 }
 
 /* called with scp->mx held */
-static void cm_LockMarkSCacheLost(cm_scache_t * scp)
+void cm_LockMarkSCacheLost(cm_scache_t * scp)
 {
     cm_file_lock_t *fileLock;
     osi_queue_t *q;
@@ -4978,7 +5000,7 @@ void cm_CheckLocks()
                 if (!IS_LOCK_ACTIVE(fileLock))
                     goto pre_syncopdone;
 
-                if (scp->serverLock != -1) {
+                if (scp->serverLock != -1 && !(scp->flags & CM_SCACHEFLAG_DELETED)) {
                     cm_fid_t cfid;
                     cm_user_t * userp;
 
@@ -5055,7 +5077,8 @@ void cm_CheckLocks()
                         }
                     }
 
-                    if (code == EINVAL || code == CM_ERROR_INVAL) {
+                    if (code == EINVAL || code == CM_ERROR_INVAL ||
+                        code == CM_ERROR_BADFD) {
                         cm_LockMarkSCacheLost(scp);
                     }