windows-unix-mode-bit-enforcement-20070105
[openafs.git] / src / WINNT / afsd / cm_vnodeops.c
index 65b3b22..d302fe5 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
 #include <winsock2.h>
-#endif /* !DJGPP */
 #include <stddef.h>
 #include <malloc.h>
 #include <string.h>
@@ -179,14 +177,16 @@ char cm_8Dot3Mapping[42] =
 };
 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
 
-void cm_Gen8Dot3Name(cm_dirEntry_t *dep, char *shortName, char **shortNameEndp)
+void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
+                        char *shortName, char **shortNameEndp)
 {
     char number[12];
     int i, nsize = 0;
-    int vnode = ntohl(dep->fid.vnode);
+    int vnode = ntohl(pfid->vnode);
     char *lastDot;
     int validExtension = 0;
-    char tc, *temp, *name;
+    char tc, *temp;
+    const char *name;
 
     /* Unparse the file's vnode number to get a "uniquifier" */
     do {
@@ -199,7 +199,7 @@ void cm_Gen8Dot3Name(cm_dirEntry_t *dep, char *shortName, char **shortNameEndp)
      * Look for valid extension.  There has to be a dot, and
      * at least one of the characters following has to be legal.
      */
-    lastDot = strrchr(dep->name, '.');
+    lastDot = strrchr(longname, '.');
     if (lastDot) {
         temp = lastDot; temp++;
         while (tc = *temp++)
@@ -210,8 +210,7 @@ void cm_Gen8Dot3Name(cm_dirEntry_t *dep, char *shortName, char **shortNameEndp)
     }       
 
     /* Copy name characters */
-    name = dep->name;
-    for (i = 0, name = dep->name;
+    for (i = 0, name = longname;
           i < (7 - nsize) && name != lastDot; ) {
         tc = *name++;
 
@@ -258,8 +257,10 @@ long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
     long code;
 
     rights = 0;
-    if (openMode != 1) rights |= PRSFS_READ;
-    if (openMode == 1 || openMode == 2 || trunc) rights |= PRSFS_WRITE;
+    if (openMode != 1) 
+       rights |= PRSFS_READ;
+    if (openMode == 1 || openMode == 2 || trunc) 
+       rights |= PRSFS_WRITE;
         
     lock_ObtainMutex(&scp->mx);
 
@@ -332,11 +333,15 @@ long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
 
 /* return success if we can open this file in this mode */
 long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
-                    unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp)
+                    unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp, 
+                   cm_lock_data_t **ldpp)
 {
     long rights;
     long code;
 
+    osi_assert(ldpp != NULL);
+    *ldpp = NULL;
+
     /* Always allow delete; the RPC will tell us if it's OK */
     if (desiredAccess == DELETE)
         return 0;
@@ -391,7 +396,18 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
 
         if (code == 0) {
-            cm_Unlock(scp, sLockType, LOffset, LLength, key, userp, reqp);
+           (*ldpp) = (cm_lock_data_t *)malloc(sizeof(cm_lock_data_t));
+           if (!*ldpp) {
+               code = ENOMEM;
+               goto _done;
+           }
+
+           (*ldpp)->key = key;
+           (*ldpp)->sLockType = sLockType;
+           (*ldpp)->LOffset.HighPart = LOffset.HighPart;
+           (*ldpp)->LOffset.LowPart = LOffset.LowPart;
+           (*ldpp)->LLength.HighPart = LLength.HighPart;
+           (*ldpp)->LLength.LowPart = LLength.LowPart;
         } else {
             /* In this case, we allow the file open to go through even
                though we can't enforce mandatory locking on the
@@ -425,6 +441,19 @@ long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
     return code;
 }
 
+extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, 
+                              cm_lock_data_t ** ldpp)
+{
+    if (*ldpp) {
+       lock_ObtainMutex(&scp->mx);
+       cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength, 
+                 (*ldpp)->key, userp, reqp);
+       lock_ReleaseMutex(&scp->mx);
+       free(*ldpp);
+       *ldpp = NULL;
+    }
+    return 0;
+}
 /*
  * When CAP_NT_SMBS has been negotiated, deletion (of files or directories) is
  * done in three steps:
@@ -452,8 +481,8 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
     /* First check permissions */
     lock_ObtainMutex(&dscp->mx);
     code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
-                      CM_SCACHESYNC_GETSTATUS
-                      | CM_SCACHESYNC_NEEDCALLBACK);
+                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     lock_ReleaseMutex(&dscp->mx);
     if (code)
         return code;
@@ -489,6 +518,7 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
         lock_ReleaseMutex(&scp->mx);
         lock_ObtainMutex(&bufferp->mx);
         lock_ObtainMutex(&scp->mx);
+       cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
         if (code)
             break;
     }
@@ -664,16 +694,16 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
             }
 
 #ifdef AFSIFS
-                       /* for the IFS version, we bulkstat the dirents because this
-                          routine is used in place of smb_ReceiveCoreSearchDir.  our
-                          other option is to modify smb_ReceiveCoreSearchDir itself, 
-                          but this seems to be the proper use for cm_ApplyDir. */
+           /* for the IFS version, we bulkstat the dirents because this
+              routine is used in place of smb_ReceiveCoreSearchDir.  our
+              other option is to modify smb_ReceiveCoreSearchDir itself, 
+              but this seems to be the proper use for cm_ApplyDir. */
             lock_ObtainMutex(&scp->mx);
             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
                  && (scp->bulkStatProgress.QuadPart <= thyper.QuadPart))
             {
                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
-                cm_TryBulkStat(scp, &thyper, userp, reqp);
+                code = cm_TryBulkStat(scp, &thyper, userp, reqp);
                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
                 scp->bulkStatProgress = thyper;
             }
@@ -695,6 +725,7 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
                     lock_ReleaseMutex(&scp->mx);
                     break;
                 }
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
                                 
                 if (cm_HaveBuffer(scp, bufferp, 1)) {
                     lock_ReleaseMutex(&scp->mx);
@@ -913,6 +944,8 @@ long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
         if (code) {
             goto done;
         }
+       cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
 
         if (cm_HaveBuffer(scp, bufp, 0)) 
             break;
@@ -1094,6 +1127,9 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
             return CM_ERROR_NOSUCHVOLUME;
         rock.fid = dscp->dotdotFid;
         goto haveFid;
+    } else if (strcmp(namep, ".") == 0) {
+       rock.fid = dscp->fid;
+       goto haveFid;
     }
 
     memset(&rock, 0, sizeof(rock));
@@ -1184,6 +1220,7 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
         cm_ReleaseSCache(tscp);
         return code;
     }
+    cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     /* tscp is now locked */
 
     if (!(flags & CM_FLAG_NOMOUNTCHASE)
@@ -1250,13 +1287,23 @@ int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
     return 1;
 }   
 
+#ifdef DEBUG_REFCOUNT
+long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
+               cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
+#else
 long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
                cm_req_t *reqp, cm_scache_t **outpScpp)
+#endif
 {
     long code;
     char tname[256];
     int sysNameIndex = 0;
-    cm_scache_t *scp = 0;
+    cm_scache_t *scp = NULL;
+
+#ifdef DEBUG_REFCOUNT
+    afsi_log("%s:%d cm_Lookup dscp 0x%p ref %d", file, line, dscp, dscp->refCount, file, line);
+    osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
+#endif
 
     if ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
         if (flags & CM_FLAG_CHECKPATH)
@@ -1269,16 +1316,27 @@ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
         code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
         if (code > 0) {
             code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
+#ifdef DEBUG_REFCOUNT
+           afsi_log("%s:%d cm_LookupInternal (1) 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 (1) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+#endif
+
             if (code == 0) {
                 *outpScpp = scp;
                 return 0;
             }
             if (scp) {
                 cm_ReleaseSCache(scp);
-                scp = 0;
+                scp = NULL;
             }
         } else {
-            return cm_LookupInternal(dscp, namep, flags, userp, reqp, outpScpp);
+            code = cm_LookupInternal(dscp, namep, flags, userp, reqp, &scp);
+#ifdef DEBUG_REFCOUNT
+           afsi_log("%s:%d cm_LookupInternal (2) code 0x%x dscp 0x%p ref %d scp 0x%p ref %d", file, line, code, dscp, dscp->refCount, scp, scp ? scp->refCount : 0);
+           osi_Log3(afsd_logp, "cm_LookupInternal (2) code 0x%x dscp 0x%p scp 0x%p", code, dscp, scp);
+#endif
+           *outpScpp = scp;
+           return code;
         }
     }
 
@@ -1344,6 +1402,13 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
     cm_SyncOpDone(dscp, NULL, sflags);
     if (code == 0) 
         cm_MergeStatus(dscp, &newDirStatus, &volSync, userp, 0);
+       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 
+                * have an inconsistent view of the world.
+                */
+               dscp->cbServerp = NULL;
+       }
     lock_ReleaseMutex(&dscp->mx);
 
     return code;
@@ -1375,6 +1440,8 @@ long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
                 buf_Release(bufp);
                 return code;
             }
+           cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
             if (cm_HaveBuffer(linkScp, bufp, 0)) 
                 break;
 
@@ -1500,9 +1567,14 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
     lock_ReleaseMutex(&linkScp->mx);
     return code;
 }
-
+#ifdef DEBUG_REFCOUNT
+long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
+               cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp, 
+              char * file, long line)
+#else
 long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
+#endif
 {
     long code;
     char *tp;                  /* ptr moving through input buffer */
@@ -1523,6 +1595,13 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
     int extraFlag;             /* avoid chasing mt pts for dir cmd */
     int phase = 1;             /* 1 = tidPathp, 2 = pathp */
 
+#ifdef DEBUG_REFCOUNT
+    afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
+    osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %s tidpath %s flags 0x%x",
+             rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
+             flags);
+#endif
+
     tp = tidPathp;
     if (tp == NULL) {
         tp = pathp;
@@ -1536,7 +1615,8 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
     tscp = rootSCachep;
     cm_HoldSCache(tscp);
     symlinkCount = 0;
-    dirScp = 0;
+    dirScp = NULL;
+
 
     while (1) {
         tc = *tp++;
@@ -1571,34 +1651,45 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                  * is a symlink, we have more to do.
                  */
                 *cp++ = 0;     /* add null termination */
-                extraFlag = 0;
-                if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
-                    extraFlag = CM_FLAG_NOMOUNTCHASE;
-                code = cm_Lookup(tscp, component,
-                                  flags | extraFlag,
-                                  userp, reqp, &nscp);
-                if (code) {
-                    cm_ReleaseSCache(tscp);
-                    if (dirScp)
+               if (!strcmp(".",component)) {
+                    code = 0;
+                    if (dirScp) {
                         cm_ReleaseSCache(dirScp);
-                    if (psp) 
-                        cm_FreeSpace(psp);
-                    if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK)
-                        return CM_ERROR_NOSUCHPATH;
-                    else
-                        return code;
-                }
-                haveComponent = 0;     /* component done */
-                if (dirScp)
-                    cm_ReleaseSCache(dirScp);
-                dirScp = tscp;         /* for some symlinks */
-                tscp = nscp;           /* already held */
-                nscp = 0;
-                if (tc == 0 && !(flags & CM_FLAG_FOLLOW) && phase == 2) {
+                        dirScp = NULL;
+                    }
+                    break;
+               }
+               extraFlag = 0;
+               if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
+                   extraFlag = CM_FLAG_NOMOUNTCHASE;
+               code = cm_Lookup(tscp, component,
+                                 flags | extraFlag,
+                                 userp, reqp, &nscp);
+               if (code) {
+                   cm_ReleaseSCache(tscp);
+                   if (dirScp)
+                       cm_ReleaseSCache(dirScp);
+                   if (psp) 
+                       cm_FreeSpace(psp);
+                   if (code == CM_ERROR_NOSUCHFILE && tscp->fileType == CM_SCACHETYPE_SYMLINK) {
+                       osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
+                       return CM_ERROR_NOSUCHPATH;
+                   } else {
+                       osi_Log1(afsd_logp,"cm_NameI code 0x%x", code);
+                       return code;
+                   }
+               }       
+               haveComponent = 0;      /* component done */
+               if (dirScp)
+                   cm_ReleaseSCache(dirScp);
+               dirScp = tscp;          /* for some symlinks */
+               tscp = nscp;            /* already held */
+               nscp = NULL;
+               if (tc == 0 && !(flags & CM_FLAG_FOLLOW) && phase == 2) {
                     code = 0;
                     if (dirScp) {
                         cm_ReleaseSCache(dirScp);
-                        dirScp = 0;
+                        dirScp = NULL;
                     }
                     break;
                 }
@@ -1613,25 +1704,28 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                 if (code) {
                     lock_ReleaseMutex(&tscp->mx);
                     cm_ReleaseSCache(tscp);
-                    tscp = 0;
+                    tscp = NULL;
                     if (dirScp) {
                         cm_ReleaseSCache(dirScp);
-                        dirScp = 0;
+                        dirScp = NULL;
                     }
                     break;
                 }
+               cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
                 if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
                     /* this is a symlink; assemble a new buffer */
                     lock_ReleaseMutex(&tscp->mx);
                     if (symlinkCount++ >= MAX_SYMLINK_COUNT) {
                         cm_ReleaseSCache(tscp);
-                        tscp = 0;
+                        tscp = NULL;
                         if (dirScp) {
                             cm_ReleaseSCache(dirScp);
-                            dirScp = 0;
+                            dirScp = NULL;
                         }
                         if (psp) 
                             cm_FreeSpace(psp);
+                       osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_TOO_MANY_SYMLINKS");
                         return CM_ERROR_TOO_MANY_SYMLINKS;
                     }
                     if (tc == 0) 
@@ -1642,10 +1736,10 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                     if (code) {
                         /* something went wrong */
                         cm_ReleaseSCache(tscp);
-                        tscp = 0;
+                        tscp = NULL;
                         if (dirScp) {
                             cm_ReleaseSCache(dirScp);
-                            dirScp = 0;
+                            dirScp = NULL;
                         }
                         break;
                     }
@@ -1664,7 +1758,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                     tp = psp->data;
                     cm_ReleaseSCache(tscp);
                     tscp = linkScp;
-                    linkScp = 0;
+                    linkScp = NULL;
                     /* already held
                      * by AssembleLink
                      * now, if linkScp is null, that's
@@ -1677,7 +1771,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                      */
                     if (tscp == NULL) {
                         tscp = dirScp;
-                        dirScp = 0;
+                        dirScp = NULL;
                     }
                 } else {
                     /* not a symlink, we may be done */
@@ -1690,7 +1784,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                         }
                         if (dirScp) {
                             cm_ReleaseSCache(dirScp);
-                            dirScp = 0;
+                            dirScp = NULL;
                         }
                         code = 0;
                         break;
@@ -1698,7 +1792,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                 }
                 if (dirScp) {
                     cm_ReleaseSCache(dirScp);
-                    dirScp = 0;
+                    dirScp = NULL;
                 }
             } /* end of a component */
             else 
@@ -1715,6 +1809,11 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
         *outScpp = tscp;
     else if (tscp)
         cm_ReleaseSCache(tscp);
+
+#ifdef DEBUG_REFCOUNT
+    afsi_log("%s:%d cm_NameI code 0x%x outScpp 0x%p ref %d", file, line, code, *outScpp, (*outScpp)->refCount);
+#endif
+    osi_Log2(afsd_logp,"cm_NameI code 0x%x outScpp 0x%p", code, *outScpp);
     return code;
 }
 
@@ -1773,7 +1872,7 @@ long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
  * check anyway, but we want to minimize the chance that we have to leave stuff
  * unstat'd.
  */
-#define CM_BULKMAX             128
+#define CM_BULKMAX             (3 * AFSCBMAX)
 
 /* rock for bulk stat calls */
 typedef struct cm_bulkStat {
@@ -1833,7 +1932,7 @@ long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
     if (tscp) {
         if (lock_TryMutex(&tscp->mx)) {
             /* we have an entry that we can look at */
-            if (cm_HaveCallback(tscp)) {
+            if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
                 /* we have a callback on it.  Don't bother
                  * fetching this stat entry, since we're happy
                  * with the info we have.
@@ -1871,11 +1970,12 @@ long cm_TryBulkProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 /* called with a locked scp and a pointer to a buffer.  Make bulk stat
  * calls on all undeleted files in the page of the directory specified.
  */
-void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
-                     cm_req_t *reqp)
+afs_int32
+cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
+              cm_req_t *reqp)
 {
     long code;
-    cm_bulkStat_t bb;  /* this is *BIG*, probably 12K or so;
+    cm_bulkStat_t bb;  /* this is *BIG*, probably 16K or so;
                          * watch for stack problems */
     AFSCBFids fidStruct;
     AFSBulkStats statStruct;
@@ -1890,13 +1990,14 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
     cm_scache_t *scp;
     cm_fid_t tfid;
     struct rx_connection * callp;
+    int inlinebulk = 0;                /* Did we use InlineBulkStatus RPC or not? */
 
     osi_Log1(afsd_logp, "cm_TryBulkStat dir 0x%p", dscp);
 
     /* should be on a buffer boundary */
     osi_assert((offsetp->LowPart & (cm_data.buf_blockSize - 1)) == 0);
 
-    bb.counter = 0;
+    memset(&bb, 0, sizeof(bb));
     bb.bufOffset = *offsetp;
 
     lock_ReleaseMutex(&dscp->mx);
@@ -1906,7 +2007,7 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
     /* if we failed, bail out early */
     if (code && code != CM_ERROR_STOPNOW) {
         lock_ObtainMutex(&dscp->mx);
-        return;
+        return code;
     }
 
     /* otherwise, we may have one or more bulk stat's worth of stuff in bb;
@@ -1933,18 +2034,29 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
                 continue;
 
             callp = cm_GetRxConn(connp);
-            code = RXAFS_BulkStatus(callp, &fidStruct,
+           if (!(connp->serverp->flags & CM_SERVERFLAG_NOINLINEBULK)) {
+               code = RXAFS_InlineBulkStatus(callp, &fidStruct,
                                      &statStruct, &callbackStruct, &volSync);
+               if (code == RXGEN_OPCODE) {
+                   cm_SetServerNoInlineBulk(connp->serverp, 0);
+               } else {
+                   inlinebulk = 1;
+               }
+           }
+           if (!inlinebulk) {
+               code = RXAFS_BulkStatus(callp, &fidStruct,
+                                       &statStruct, &callbackStruct, &volSync);
+           }
             rx_PutConnection(callp);
 
         } while (cm_Analyze(connp, userp, reqp, &dscp->fid,
                              &volSync, NULL, &cbReq, code));
         code = cm_MapRPCError(code, reqp);
-
         if (code)
-            osi_Log1(afsd_logp, "CALL BulkStatus FAILURE code 0x%x", code);
+            osi_Log2(afsd_logp, "CALL %sBulkStatus FAILURE code 0x%x", 
+                     inlinebulk ? "Inline" : "", code);
         else
-            osi_Log0(afsd_logp, "CALL BulkStatus SUCCESS");
+            osi_Log1(afsd_logp, "CALL %sBulkStatus SUCCESS", inlinebulk ? "Inline" : "");
 
         /* may as well quit on an error, since we're not going to do
          * much better on the next immediate call, either.
@@ -1979,7 +2091,7 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
              * Right now, be pretty conservative: if there's a
              * callback or a pending call, skip it.
              */
-            if (scp->cbServerp == NULL
+            if ((scp->cbServerp == NULL || (scp->flags & CM_SCACHEFLAG_EACCESS))
                  && !(scp->flags &
                        (CM_SCACHEFLAG_FETCHING
                          | CM_SCACHEFLAG_STORING
@@ -1987,8 +2099,7 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
                 cm_EndCallbackGrantingCall(scp, &cbReq,
                                             &bb.callbacks[j],
                                             CM_CALLBACK_MAINTAINCOUNT);
-                cm_MergeStatus(scp, &bb.stats[j], &volSync,
-                                userp, 0);
+                cm_MergeStatus(scp, &bb.stats[j], &volSync, userp, 0);
             }       
             lock_ReleaseMutex(&scp->mx);
             cm_ReleaseSCache(scp);
@@ -2000,7 +2111,23 @@ void cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp, cm_user_t *userp,
         filex += filesThisCall;
     }  /* while there are still more files to process */
     lock_ObtainMutex(&dscp->mx);
-    osi_Log0(afsd_logp, "END cm_TryBulkStat");
+
+#if 0
+    /* If we did the InlineBulk RPC pull out the return code */
+    if (inlinebulk) {
+       if ((&bb.stats[0])->errorCode) {
+           cm_Analyze(NULL /*connp was released by the previous cm_Analyze */, 
+                       userp, reqp, &dscp->fid, &volSync, NULL, NULL, (&bb.stats[0])->errorCode);
+           code = cm_MapRPCError((&bb.stats[0])->errorCode, reqp);
+       }
+    } else
+#endif 
+    { 
+       code = 0;
+    }
+
+    osi_Log1(afsd_logp, "END cm_TryBulkStat code = 0x%x", code);
+    return code;
 }       
 
 void cm_StatusFromAttr(AFSStoreStatus *statusp, cm_scache_t *scp, cm_attr_t *attrp)
@@ -2061,7 +2188,8 @@ long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) 
         goto done;
-        
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     if (scp->fileType != CM_SCACHETYPE_FILE) {
         code = CM_ERROR_ISDIR;
         goto done;
@@ -2120,6 +2248,10 @@ long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
     /* done successfully */
     code = 0;
 
+    cm_SyncOpDone(scp, NULL, 
+                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+                  | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
+
   done:
     lock_ReleaseMutex(&scp->mx);
     lock_ReleaseWrite(&scp->bufCreateLock);
@@ -2132,7 +2264,6 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
                 cm_req_t *reqp)
 {
     long code;
-    int flags;
     AFSFetchStatus afsOutStatus;
     AFSVolSync volSync;
     cm_conn_t *connp;
@@ -2144,11 +2275,13 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
     if (attrp->mask & CM_ATTRMASK_LENGTH)
         return cm_SetLength(scp, &attrp->length, userp, reqp);
 
-    flags = CM_SCACHESYNC_STORESTATUS;
-
     lock_ObtainMutex(&scp->mx);
     /* otherwise, we have to make an RPC to get the status */
     code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
+    if (code) {
+       lock_ReleaseMutex(&scp->mx);
+        return code;
+    }
 
     /* make the attr structure */
     cm_StatusFromAttr(&afsInStatus, scp, attrp);
@@ -2156,10 +2289,7 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
     tfid.Volume = scp->fid.volume;
     tfid.Vnode = scp->fid.vnode;
     tfid.Unique = scp->fid.unique;
-
-    lock_ReleaseMutex(&scp->mx);
-    if (code) 
-        return code;
+       lock_ReleaseMutex(&scp->mx);
 
     /* now make the RPC */
     osi_Log1(afsd_logp, "CALL StoreStatus scp 0x%p", scp);
@@ -2314,12 +2444,17 @@ long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     lock_ReleaseWrite(&scp->bufCreateLock);
     if (code == 0) {
         lock_ObtainMutex(&scp->mx);
-        scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA
-                         | CM_SCACHEFLAG_OUTOFSPACE);
+
         if (scp->mask & (CM_SCACHEMASK_TRUNCPOS
                           | CM_SCACHEMASK_CLIENTMODTIME
                           | CM_SCACHEMASK_LENGTH))
             code = cm_StoreMini(scp, userp, reqp);
+
+        if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
+           code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
+           scp->flags &= ~(CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE);
+       }
+
         lock_ReleaseMutex(&scp->mx);
     }
     return code;
@@ -2723,7 +2858,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
                 lock_ReleaseMutex(&newDscp->mx);
                 if (code) {
                     /* cleanup first one */
-                    lock_ObtainMutex(&newDscp->mx);
+                    lock_ObtainMutex(&oldDscp->mx);
                     cm_SyncOpDone(oldDscp, NULL,
                                    CM_SCACHESYNC_STOREDATA);
                     lock_ReleaseMutex(&oldDscp->mx);
@@ -3438,7 +3573,7 @@ long cm_LockCheckPerms(cm_scache_t * scp,
     if (lock_type == LockRead)
         rights |= PRSFS_LOCK;
     else if (lock_type == LockWrite)
-        rights |= PRSFS_WRITE;
+        rights |= PRSFS_WRITE | PRSFS_LOCK;
     else {
         /* hmmkay */
         osi_assert(FALSE);
@@ -3453,7 +3588,6 @@ long cm_LockCheckPerms(cm_scache_t * scp,
         lock_type == LockWrite &&
        scp->creator == userp) {
         /* check for PRSFS_INSERT. */
-        cm_ucell_t * ucp;
 
         code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_INSERT,
                          CM_SCACHESYNC_GETSTATUS |
@@ -3463,7 +3597,8 @@ long cm_LockCheckPerms(cm_scache_t * scp,
            osi_Log0(afsd_logp, "cm_LockCheckPerms user is creator but has no INSERT bits for scp");
     }
 
- return_code:
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     osi_Log1(afsd_logp, "cm_LockCheckPerms returning code %d", code);
 
     return code;
@@ -3568,7 +3703,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
             }
 
         } else if ((scp->exclusiveLocks > 0) ||
-                (scp->sharedLocks > 0 && scp->serverLock != LockRead)) {
+                   (scp->sharedLocks > 0 && scp->serverLock != LockRead)) {
 
             /* We are already waiting for some other lock.  We should
                wait for the daemon to catch up instead of generating a
@@ -3604,7 +3739,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
             }
 
             if (scp->serverLock == LockRead && Which == LockWrite) {
-            
+
                 /* We want to escalate the lock to a LockWrite.
                    Unfortunately that's not really possible without
                    letting go of the current lock.  But for now we do
@@ -3646,7 +3781,7 @@ long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
 
                 /* am I sane? */
                 osi_assert(newLock == LockRead);
-                
+
                 code = cm_IntSetLock(scp, userp, newLock, reqp);
             }
 
@@ -3832,7 +3967,7 @@ long cm_UnlockByKey(cm_scache_t * scp,
 
             if (scp->fileLocksT == q)
                 scp->fileLocksT = osi_QPrev(q);
-            osi_QRemove(&scp->fileLocksH,q);
+            osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
 
             if (IS_LOCK_CLIENTONLY(fileLock)) {
                 scp->clientLocks--;
@@ -4020,7 +4155,7 @@ long cm_Unlock(cm_scache_t *scp,
     lock_ObtainWrite(&cm_scacheLock);
     if (scp->fileLocksT == q)
         scp->fileLocksT = osi_QPrev(q);
-    osi_QRemove(&scp->fileLocksH, q);
+    osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, q);
 
     /*
      * Don't delete it here; let the daemon delete it, to simplify
@@ -4457,9 +4592,9 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
     /* Check if we already have a sufficient server lock to allow this
        lock to go through. */
     if (IS_LOCK_WAITLOCK(oldFileLock) &&
-       (!SERVERLOCKS_ENABLED(scp) ||
-        scp->serverLock == oldFileLock->lockType ||
-        scp->serverLock == LockWrite)) {
+        (!SERVERLOCKS_ENABLED(scp) ||
+         scp->serverLock == oldFileLock->lockType ||
+         scp->serverLock == LockWrite)) {
 
         oldFileLock->flags &= ~CM_FILELOCK_FLAG_WAITLOCK;
 
@@ -4500,7 +4635,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
             }
 
             if (IS_LOCK_ACCEPTED(fileLock) &&
-               INTERSECT_RANGE(oldFileLock->range, fileLock->range)) {
+                INTERSECT_RANGE(oldFileLock->range, fileLock->range)) {
 
                 if (oldFileLock->lockType != LockRead ||
                    fileLock->lockType != LockRead) {
@@ -4605,7 +4740,7 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
        lock_ObtainWrite(&cm_scacheLock);
         if (scp->fileLocksT == &oldFileLock->fileq)
             scp->fileLocksT = osi_QPrev(&oldFileLock->fileq);
-        osi_QRemove(&scp->fileLocksH, &oldFileLock->fileq);
+        osi_QRemoveHT(&scp->fileLocksH, &scp->fileLocksT, &oldFileLock->fileq);
        lock_ReleaseWrite(&cm_scacheLock);
     } else if (code == 0 && IS_LOCK_WAITLOCK(oldFileLock)) {
         scp->serverLock = newLock;