DEVEL15-windows-largefile-support-20060623
[openafs.git] / src / WINNT / afsd / smb.c
index 4e16c12..3af0993 100644 (file)
 #include <stdio.h>
 #include <time.h>
 
+#include "afsd.h"
 #include <osi.h>
 #include <rx\rx.h>
 #include <rx/rx_prototypes.h>
-
-#include "afsd.h"
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
@@ -38,8 +37,6 @@
 static char *illegalChars = "\\/:*?\"<>|";
 BOOL isWindows2000 = FALSE;
 
-smb_vc_t *active_vcp = NULL;
-
 int smbShutdownFlag = 0;
 
 int smb_LogoffTokenTransfer;
@@ -172,6 +169,8 @@ smb_username_t *usernamesp = NULL;
 
 smb_waitingLockRequest_t *smb_allWaitingLocks;
 
+DWORD smb_TlsRequestSlot = -1;
+
 /* forward decl */
 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                        NCB *ncbp, raw_write_cont_t *rwcp);
@@ -206,6 +205,40 @@ int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
 /* Faux server GUID. This is never checked. */
 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
 
+void smb_ResetServerPriority()
+{
+    void * p = TlsGetValue(smb_TlsRequestSlot);
+    if (p) {
+       free(p);
+       TlsSetValue(smb_TlsRequestSlot, NULL);
+       SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+    }
+}
+
+void smb_SetRequestStartTime()
+{
+    time_t * tp = malloc(sizeof(time_t));
+    if (tp) {
+       *tp = osi_Time();
+
+       if (!TlsSetValue(smb_TlsRequestSlot, tp))
+           free(tp);
+    }  
+}
+
+void smb_UpdateServerPriority()
+{      
+    time_t *tp = TlsGetValue(smb_TlsRequestSlot);
+
+    if (tp) {
+       time_t now = osi_Time();
+
+       /* Give one priority boost for each 15 seconds */
+       SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
+    }
+}
+
+
 const char * ncb_error_string(int code)
 {
     const char * s;
@@ -317,6 +350,8 @@ char * myCrt_Dispatch(int i)
         return "(2d)ReceiveV3OpenX";
     case 0x2e:
         return "(2e)ReceiveV3ReadX";
+    case 0x2f:
+        return "(2f)ReceiveV3WriteX";
     case 0x32:
         return "(32)ReceiveV3Tran2A";
     case 0x33:
@@ -795,7 +830,7 @@ void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
     struct tm localJunk;
     time_t t = unixTime;
 
-    ltp = localtime((time_t*) &t);
+    ltp = localtime(&t);
 
     /* if we fail, make up something */
     if (!ltp) {
@@ -858,7 +893,12 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
 
     lock_ObtainWrite(&smb_rctLock);
     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
-        if (lsn == vcp->lsn && lana == vcp->lana) {
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+        if (lsn == vcp->lsn && lana == vcp->lana &&
+           !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
             smb_HoldVCNoLock(vcp);
             break;
         }
@@ -869,6 +909,7 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
        lock_ObtainWrite(&smb_globalLock);
         vcp->vcID = ++numVCs;
        lock_ReleaseWrite(&smb_globalLock);
+       vcp->magic = SMB_VC_MAGIC;
         vcp->refCount = 2;     /* smb_allVCsp and caller */
         vcp->tidCounter = 1;
         vcp->fidCounter = 1;
@@ -936,24 +977,40 @@ int smb_IsStarMask(char *maskp)
 void smb_ReleaseVCInternal(smb_vc_t *vcp)
 {
     smb_vc_t **vcpp;
+    smb_vc_t * avcp;
 
-#ifdef DEBUG
-    osi_assert(vcp->refCount-- != 0);
-#else
     vcp->refCount--;
-#endif
 
     if (vcp->refCount == 0) {
+      if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
        /* remove VCP from smb_deadVCsp */
        for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
-           if (*vcpp == vcp) {
-               *vcpp = vcp->nextp;
-               break;
-           }
+         if (*vcpp == vcp) {
+           *vcpp = vcp->nextp;
+           break;
+         }
        } 
        lock_FinalizeMutex(&vcp->mx);
        memset(vcp,0,sizeof(smb_vc_t));
        free(vcp);
+      } else {
+       for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
+         if (avcp == vcp)
+           break;
+       }
+       osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
+                avcp?"not ":"",vcp, vcp->refCount);
+#ifdef DEBUG
+       GenerateMiniDump(NULL);
+#endif
+       /* This is a wrong.  However, I suspect that there is an undercount
+        * and I don't want to release 1.4.1 in a state that will allow
+        * smb_vc_t objects to be deallocated while still in the
+        * smb_allVCsp list.  The list is supposed to keep a reference
+        * to the smb_vc_t.  Put it back.
+        */
+       vcp->refCount++;
+      }
     }
 }
 
@@ -997,13 +1054,36 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     smb_user_t *uidpNext;
     smb_vc_t **vcpp;
 
+
+    lock_ObtainMutex(&vcp->mx);
+    if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
+       lock_ReleaseMutex(&vcp->mx);
+       osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
+       return;
+    }
+    vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
+    lock_ReleaseMutex(&vcp->mx);
     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
 
     lock_ObtainWrite(&smb_rctLock);
+    /* remove VCP from smb_allVCsp */
+    for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
+       if ((*vcpp)->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+        if (*vcpp == vcp) {
+            *vcpp = vcp->nextp;
+            vcp->nextp = smb_deadVCsp;
+            smb_deadVCsp = vcp;
+           /* Hold onto the reference until we are done with this function */
+            break;
+        }
+    }
+
     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
 
-        if (fidpIter->flags & SMB_FID_DELETE)
+        if (fidpIter->delete)
             continue;
 
         fid = fidpIter->fid;
@@ -1012,7 +1092,6 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
        smb_HoldFIDNoLock(fidpIter);
         lock_ReleaseWrite(&smb_rctLock);
 
-       /* smb_CloseFID sets SMB_FID_DELETE on Success */
         smb_CloseFID(vcp, fidpIter, NULL, 0);
        smb_ReleaseFID(fidpIter);
 
@@ -1022,9 +1101,9 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
 
     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
        tidpNext = tidpIter->nextp;
-
-       if (tidpIter->flags & SMB_TIDFLAG_DELETE)
+       if (tidpIter->delete)
            continue;
+       tidpIter->delete = 1;
 
        tid = tidpIter->tid;
        osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
@@ -1032,10 +1111,6 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
        smb_HoldTIDNoLock(tidpIter);
        lock_ReleaseWrite(&smb_rctLock);
 
-       lock_ObtainMutex(&tidpIter->mx);
-       tidpIter->flags |= SMB_TIDFLAG_DELETE;
-       lock_ReleaseMutex(&tidpIter->mx);
-
        smb_ReleaseTID(tidpIter);
 
        lock_ObtainWrite(&smb_rctLock);
@@ -1044,38 +1119,24 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
 
     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
        uidpNext = uidpIter->nextp;
-
-       if (uidpIter->flags & SMB_USERFLAG_DELETE)
+       if (uidpIter->delete)
            continue;
+       uidpIter->delete = 1;
 
        /* do not add an additional reference count for the smb_user_t
         * as the smb_vc_t already is holding a reference */
        lock_ReleaseWrite(&smb_rctLock);
 
-       lock_ObtainMutex(&uidpIter->mx);
-       uidpIter->flags |= SMB_USERFLAG_DELETE;
-       lock_ReleaseMutex(&uidpIter->mx);
-
        smb_ReleaseUID(uidpIter);
 
        lock_ObtainWrite(&smb_rctLock);
        uidpNext = vcp->usersp;
     }
 
-    /* remove VCP from smb_allVCsp */
-    for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
-       if (*vcpp == vcp) {
-           *vcpp = vcp->nextp;
-           vcp->nextp = smb_deadVCsp;
-           smb_deadVCsp = vcp;
-           /* We intentionally do not keep a reference to the 
-            * vcp once it is placed on the deadVCsp list.  This
-            * allows the refcount to reach 0 so we can delete
-            * it. */
-           smb_ReleaseVCNoLock(vcp);
-           break;
-       }
-    } 
+    /* The vcp is now on the deadVCsp list.  We intentionally drop the
+     * reference so that the refcount can reach 0 and we can delete it */
+    smb_ReleaseVCNoLock(vcp);
+    
     lock_ReleaseWrite(&smb_rctLock);
     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
 }
@@ -1120,7 +1181,7 @@ void smb_ReleaseTID(smb_tid_t *tidp)
     userp = NULL;
     lock_ObtainWrite(&smb_rctLock);
     osi_assert(tidp->refCount-- > 0);
-    if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
+    if (tidp->refCount == 0 && (tidp->delete)) {
         ltpp = &tidp->vcp->tidsp;
         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
             if (tp == tidp) 
@@ -1288,11 +1349,29 @@ void smb_ReleaseUID(smb_user_t *uidp)
     }
 }      
 
+cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
+{
+    cm_user_t *up = NULL;
+
+    if (!uidp)
+       return NULL;
+    
+    lock_ObtainMutex(&uidp->mx);
+    if (uidp->unp) {
+       up = uidp->unp->userp;
+       cm_HoldUser(up);
+    }
+    lock_ReleaseMutex(&uidp->mx);
+
+    return up;
+}
+
+
 /* retrieve a held reference to a user structure corresponding to an incoming
  * request.
  * corresponding release function is cm_ReleaseUser.
  */
-cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
+cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
 {
     smb_user_t *uidp;
     cm_user_t *up = NULL;
@@ -1303,12 +1382,7 @@ cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
     if (!uidp)
        return NULL;
     
-    lock_ObtainMutex(&uidp->mx);
-    if (uidp->unp) {
-       up = uidp->unp->userp;
-       cm_HoldUser(up);
-    }
-    lock_ReleaseMutex(&uidp->mx);
+    up = smb_GetUserFromUID(uidp);
 
     smb_ReleaseUID(uidp);
     return up;
@@ -1444,10 +1518,10 @@ void smb_ReleaseFID(smb_fid_t *fidp)
     smb_vc_t *vcp = NULL;
     smb_ioctl_t *ioctlp;
 
+    lock_ObtainMutex(&fidp->mx);
     lock_ObtainWrite(&smb_rctLock);
     osi_assert(fidp->refCount-- > 0);
-    lock_ObtainMutex(&fidp->mx);
-    if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
+    if (fidp->refCount == 0 && (fidp->delete)) {
         vcp = fidp->vcp;
         fidp->vcp = NULL;
         scp = fidp->scp;    /* release after lock is released */
@@ -1455,7 +1529,8 @@ void smb_ReleaseFID(smb_fid_t *fidp)
         userp = fidp->userp;
         fidp->userp = NULL;
 
-        osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
+       if (vcp->fidsp) 
+           osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
         thrd_CloseHandle(fidp->raw_write_event);
 
         /* and see if there is ioctl stuff to free */
@@ -1469,7 +1544,6 @@ void smb_ReleaseFID(smb_fid_t *fidp)
                 free(ioctlp->outAllocp);
             free(ioctlp);
         }       
-
        lock_ReleaseMutex(&fidp->mx);
        lock_FinalizeMutex(&fidp->mx);
         free(fidp);
@@ -2485,16 +2559,19 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
 #endif /* !DJGPP */
 
-       osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
-                vcp, vcp->usersp);
-
-       lock_ObtainWrite(&smb_globalLock);
-       lock_ObtainMutex(&vcp->mx);
-       vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-       dead_sessions[vcp->session] = TRUE;
-       lock_ReleaseMutex(&vcp->mx);
-       lock_ReleaseWrite(&smb_globalLock);
-       smb_CleanupDeadVC(vcp);
+       lock_ObtainMutex(&vcp->mx);
+       if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+           osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
+                     vcp, vcp->usersp);
+           vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+           lock_ReleaseMutex(&vcp->mx);
+           lock_ObtainWrite(&smb_globalLock);
+           dead_sessions[vcp->session] = TRUE;
+           lock_ReleaseWrite(&smb_globalLock);
+           smb_CleanupDeadVC(vcp);
+       } else {
+           lock_ReleaseMutex(&vcp->mx);
+       }
     }
 
     if (localNCB)
@@ -2889,11 +2966,32 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     fd = smb_GetSMBParm(inp, 0);
     count = smb_GetSMBParm(inp, 3);
     minCount = smb_GetSMBParm(inp, 4);
-    offset.HighPart = 0;       /* too bad */
     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
 
-    osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
-             fd, offset.LowPart, count);
+    if (*inp->wctp == 10) {
+        /* we were sent a request with 64-bit file offsets */
+#ifdef AFS_LARGEFILES
+        offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
+
+        if (LargeIntegerLessThanZero(offset)) {
+            osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
+            goto send1;
+        }
+#else
+        if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
+            osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
+            goto send1;
+        } else {
+            offset.HighPart = 0;
+        }
+#endif
+    } else {
+        /* we were sent a request with 32-bit file offsets */
+        offset.HighPart = 0;
+    }
+
+    osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
+             fd, offset.HighPart, offset.LowPart, count);
 
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp)
@@ -2906,7 +3004,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
 
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
-        LOffset.HighPart = 0;
+        LOffset.HighPart = offset.HighPart;
         LOffset.LowPart = offset.LowPart;
         LLength.HighPart = 0;
         LLength.LowPart = count;
@@ -2960,7 +3058,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     }
     lock_ReleaseMutex(&fidp->mx);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
 #ifndef DJGPP
     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
@@ -3143,6 +3241,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
 #endif
+#ifdef AFS_LARGEFILES
+               NTNEGOTIATE_CAPABILITY_LARGEFILES |
+#endif
                NTNEGOTIATE_CAPABILITY_NTFIND |
                NTNEGOTIATE_CAPABILITY_RAWMODE |
                NTNEGOTIATE_CAPABILITY_NTSMB;
@@ -3244,15 +3345,25 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 void smb_CheckVCs(void)
 {
-    smb_vc_t * vcp;
+    smb_vc_t * vcp, *nextp;
     smb_packet_t * outp = GetPacket();
     smb_t *smbp;
             
-    for ( vcp=smb_allVCsp; vcp; vcp = vcp->nextp ) 
+    lock_ObtainWrite(&smb_rctLock);
+    for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
     {
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+       nextp = vcp->nextp;
+
        if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
            continue;
 
+       smb_HoldVCNoLock(vcp);
+       if (nextp)
+           smb_HoldVCNoLock(nextp);
        smb_FormatResponsePacket(vcp, NULL, outp);
         smbp = (smb_t *)outp;
        outp->inCom = smbp->com = 0x2b /* Echo */;
@@ -3265,10 +3376,16 @@ void smb_CheckVCs(void)
 
        smb_SetSMBParm(outp, 0, 0);
        smb_SetSMBDataLength(outp, 0);
+       lock_ReleaseWrite(&smb_rctLock);
 
        smb_SendPacket(vcp, outp);
-    }
 
+       lock_ObtainWrite(&smb_rctLock);
+       smb_ReleaseVCNoLock(vcp);
+       if (nextp)
+           smb_ReleaseVCNoLock(nextp);
+    }
+    lock_ReleaseWrite(&smb_rctLock);
     smb_FreePacket(outp);
 }
 
@@ -3531,14 +3648,13 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         return CM_ERROR_BADSMB;
     strcpy(shareName, tp+1);
 
-    userp = smb_GetUser(vcp, inp);
-
     lock_ObtainMutex(&vcp->mx);
     newTid = vcp->tidCounter++;
     lock_ReleaseMutex(&vcp->mx);
 
     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+    userp = smb_GetUserFromUID(uidp);
     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
     if (uidp)
         smb_ReleaseUID(uidp);
@@ -3957,7 +4073,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
              nextCookie, dsp->cookie, attribute);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* try to get the vnode for the path name next */
     lock_ObtainMutex(&dsp->mx);
@@ -4389,7 +4505,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         
     rootScp = cm_data.rootSCachep;
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -4473,7 +4589,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     rootScp = cm_data.rootSCachep;
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -4489,7 +4605,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         cm_ReleaseUser(userp);
         return code;
     }
-       
+
 #ifdef DFS_SUPPORT
     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
         cm_ReleaseSCache(newScp);
@@ -4586,7 +4702,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     rootScp = cm_data.rootSCachep;
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* we shouldn't need this for V3 requests, but we seem to */
     caseFold = CM_FLAG_CASEFOLD;
@@ -4682,7 +4798,8 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
      * in a readonly volume doesn't mean it shojuld be marked as RO 
      */
     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
-        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
+        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+       newScp->fileType == CM_SCACHETYPE_INVALID)
         attrs = SMB_ATTR_DIRECTORY;
     else
         attrs = 0;
@@ -4722,9 +4839,9 @@ long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_
     /* find the tree and free it */
     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
     if (tidp) {
-        lock_ObtainMutex(&tidp->mx);
-        tidp->flags |= SMB_TIDFLAG_DELETE;
-        lock_ReleaseMutex(&tidp->mx);
+       lock_ObtainWrite(&smb_rctLock);
+        tidp->delete = 1;
+        lock_ReleaseWrite(&smb_rctLock);
         smb_ReleaseTID(tidp);
     }
 
@@ -4790,7 +4907,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -4963,7 +5080,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
 
@@ -5102,7 +5219,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     DWORD filter;
     cm_req_t req;
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -5280,7 +5397,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     DWORD filter;
     cm_req_t req;
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
     if (code) {
@@ -5394,7 +5511,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     /* now create the hardlink */
     osi_Log1(smb_logp,"  Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
-    osi_Log1(smb_logp,"  Link returns %d", code);
+    osi_Log1(smb_logp,"  Link returns 0x%x", code);
 
     /* Handle Change Notification */
     if (code == 0) {
@@ -5510,7 +5627,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -5598,14 +5715,19 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
     lock_ReleaseMutex(&fidp->mx);
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_OPENWRITE)
-        code = cm_FSync(fidp->scp, userp, &req);
-    else 
+    if (fidp->flags & SMB_FID_OPENWRITE) {
+       cm_scache_t * scp = fidp->scp;
+       cm_HoldSCache(scp);
+       lock_ReleaseMutex(&fidp->mx);
+        code = cm_FSync(scp, userp, &req);
+       cm_ReleaseSCache(scp);
+    } else {
         code = 0;
-    lock_ReleaseMutex(&fidp->mx);
+       lock_ReleaseMutex(&fidp->mx);
+    }
         
     smb_ReleaseFID(fidp);
         
@@ -5667,6 +5789,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     cm_req_t req;
     cm_scache_t *dscp = fidp->NTopen_dscp;
     char *pathp = fidp->NTopen_pathp;
+    cm_scache_t * scp;
 
     osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
              fidp, fidp->fid, vcp);
@@ -5686,16 +5809,16 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     cm_InitReq(&req);
 
-    lock_ObtainMutex(&fidp->mx);
-
-    if (fidp->flags & SMB_FID_DELETE) {
+    lock_ObtainWrite(&smb_rctLock);
+    if (fidp->delete) {
        osi_Log0(smb_logp, "  Fid already closed.");
-       lock_ReleaseMutex(&fidp->mx);
+       lock_ReleaseWrite(&smb_rctLock);
        return CM_ERROR_BADFD;
     }
+    fidp->delete = 1;
+    lock_ReleaseWrite(&smb_rctLock);
 
-    fidp->flags |= SMB_FID_DELETE;
-        
+    lock_ObtainMutex(&fidp->mx);
     /* Don't jump the gun on an async raw write */
     while (fidp->raw_writers) {
         lock_ReleaseMutex(&fidp->mx);
@@ -5703,33 +5826,38 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         lock_ObtainMutex(&fidp->mx);
     }
 
+    scp = fidp->scp;
+    if (scp)
+       cm_HoldSCache(scp);
+
     /* watch for ioctl closes, and read-only opens */
-    if (fidp->scp != NULL &&
+    if (scp != NULL &&
         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
          == SMB_FID_OPENWRITE) {
         if (dosTime != 0 && dosTime != -1) {
-            fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+            scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
             /* This fixes defect 10958 */
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
         }
-        code = cm_FSync(fidp->scp, userp, &req);
+       lock_ReleaseMutex(&fidp->mx);
+        code = cm_FSync(scp, userp, &req);
+       lock_ObtainMutex(&fidp->mx);
     }
     else 
         code = 0;
 
     /* unlock any pending locks */
-    if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
-        fidp->scp->fileType == CM_SCACHETYPE_FILE) {
+    if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
+        scp->fileType == CM_SCACHETYPE_FILE) {
         cm_key_t key;
-        cm_scache_t * scp;
         long tcode;
 
-        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
+       lock_ReleaseMutex(&fidp->mx);
+
+       /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
            in zero. */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
-        scp = fidp->scp;
-        cm_HoldSCache(scp);
         lock_ObtainMutex(&scp->mx);
 
         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -5750,14 +5878,15 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     post_syncopdone:
 
         lock_ReleaseMutex(&scp->mx);
-        cm_ReleaseSCache(scp);
+       lock_ObtainMutex(&fidp->mx);
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
         char *fullPathp;
 
-        smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
-        if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+       lock_ReleaseMutex(&fidp->mx);
+        smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
+        if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_REMOVED,
@@ -5771,9 +5900,20 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                                  dscp, fullPathp, NULL, TRUE);
         }
         free(fullPathp);
+       lock_ObtainMutex(&fidp->mx);
        fidp->flags &= ~SMB_FID_DELONCLOSE;
     }
 
+    /* if this was a newly created file, then clear the creator
+     * in the stat cache entry. */
+    if (fidp->flags & SMB_FID_CREATED) {
+        lock_ObtainMutex(&scp->mx);
+       if (scp->creator == userp)
+           scp->creator = NULL;
+       lock_ReleaseMutex(&scp->mx);
+       fidp->flags &= ~SMB_FID_CREATED;
+    }
+
     if (fidp->flags & SMB_FID_NTOPEN) {
        fidp->NTopen_dscp = NULL;
         fidp->NTopen_pathp = NULL;
@@ -5788,6 +5928,9 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     if (dscp)
        cm_ReleaseSCache(dscp);
 
+    if (scp)
+       cm_ReleaseSCache(scp);
+
     if (pathp)
        free(pathp);
 
@@ -5813,7 +5956,7 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     code = smb_CloseFID(vcp, fidp, userp, dosTime);
     
@@ -5864,6 +6007,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         if (fidp->curr_chunk == fidp->prev_chunk + 1)
             sequential = 1;
     }
+    lock_ReleaseMutex(&fidp->mx);
 
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -5966,7 +6110,6 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
   done:
     lock_ReleaseMutex(&scp->mx);
-    lock_ReleaseMutex(&fidp->mx);
     if (bufferp) 
         buf_Release(bufferp);
 
@@ -6016,9 +6159,20 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     offset = *offsetp;
 
     lock_ObtainMutex(&fidp->mx);
+    /* make sure we have a writable FD */
+    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
+       osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
+                 fidp->fid, fidp->flags);
+       lock_ReleaseMutex(&fidp->mx);
+        code = CM_ERROR_BADFDOP;
+        goto done;
+    }
+    
     scp = fidp->scp;
-    lock_ObtainMutex(&scp->mx);
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
 
+    lock_ObtainMutex(&scp->mx);
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
@@ -6027,13 +6181,6 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     if (code) 
         goto done;
         
-    /* make sure we have a writable FD */
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       lock_ReleaseMutex(&fidp->mx);
-        code = CM_ERROR_BADFDOP;
-        goto done;
-    }
-
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
     minLength = fileLength;
@@ -6200,6 +6347,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         buf_Release(bufferp);
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
@@ -6214,14 +6362,16 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
                   fidp->fid);
         code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
-        osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
-                  fidp->fid,code2);
+        osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
+                  fidp->fid, code2);
         lock_ReleaseMutex(&scp->mx);
         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
     }
 
-    osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
+    cm_ReleaseSCache(scp);
+
+    osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
               fidp->fid, code, *writtenp);
     return code;
 }
@@ -6263,7 +6413,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        return code;
     }
     lock_ReleaseMutex(&fidp->mx);
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* special case: 0 bytes transferred means truncate to this position */
     if (count == 0) {
@@ -6331,7 +6481,8 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        if (code == 0 && written == 0)
             code = CM_ERROR_PARTIALWRITE;
 
-        offset.LowPart += written;
+        offset = LargeIntegerAdd(offset,
+                                 ConvertLongToLargeInteger(written));
         count -= written;
         total_written += written;
         written = 0;
@@ -6367,10 +6518,10 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
     fd = smb_GetSMBParm(inp, 0);
     fidp = smb_FindFID(vcp, fd, 0);
 
-    osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
-             rwcp->offset.LowPart, rwcp->count);
+    osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
+             rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
 #ifndef DJGPP
     rawBuf = rwcp->buf;
@@ -6441,16 +6592,44 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     fd = smb_GetSMBParm(inp, 0);
     totalCount = smb_GetSMBParm(inp, 1);
     count = smb_GetSMBParm(inp, 10);
-    offset.HighPart = 0;       /* too bad */
-    offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
     writeMode = smb_GetSMBParm(inp, 7);
 
     op = (char *) inp->data;
     op += smb_GetSMBParm(inp, 11);
 
+    offset.HighPart = 0;
+    offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
+
+    if (*inp->wctp == 14) {
+        /* we received a 64-bit file offset */
+#ifdef AFS_LARGEFILES
+        offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
+
+        if (LargeIntegerLessThanZero(offset)) {
+            osi_Log2(smb_logp,
+                     "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
+                     offset.HighPart, offset.LowPart);
+            return CM_ERROR_BADSMB;
+        }
+#else
+        if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
+            osi_Log0(smb_logp,
+                     "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
+            return CM_ERROR_BADSMB;
+        }
+
+        offset.HighPart = 0;
+#endif
+    } else {
+        offset.HighPart = 0;    /* 32-bit file offset */
+    }
+    
     osi_Log4(smb_logp,
-             "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
-             fd, offset.LowPart, count, writeMode);
+             "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
+             fd, offset.HighPart, offset.LowPart, count);
+    osi_Log1(smb_logp,
+             "               WriteRaw WriteMode 0x%x",
+             writeMode);
         
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
@@ -6482,7 +6661,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
     }
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /*
      * Work around bug in NT client
@@ -6511,7 +6690,9 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
        if (code == 0 && written == 0)
             code = CM_ERROR_PARTIALWRITE;
 
-        offset.LowPart += written;
+        offset = LargeIntegerAdd(offset,
+                                 ConvertLongToLargeInteger(written));
+
         count -= written;
         total_written += written;
         written = 0;
@@ -6555,10 +6736,13 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return code;
     }
 
+    offset = LargeIntegerAdd(offset,
+                             ConvertLongToLargeInteger(count));
+
     rwcp->code = 0;
     rwcp->buf = rawBuf;
-    rwcp->offset.HighPart = 0;
-    rwcp->offset.LowPart = offset.LowPart + count;
+    rwcp->offset.HighPart = offset.HighPart;
+    rwcp->offset.LowPart = offset.LowPart;
     rwcp->count = totalCount - count;
     rwcp->writeMode = writeMode;
     rwcp->alreadyWritten = total_written;
@@ -6626,7 +6810,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return code;
     }
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* remember this for final results */
     smb_SetSMBParm(outp, 0, count);
@@ -6700,7 +6884,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -6803,6 +6987,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     afs_uint32 dosTime;
     char *tidPathp;
     cm_req_t req;
+    int created = 0;                   /* the file was new */
 
     cm_InitReq(&req);
 
@@ -6824,7 +7009,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -6902,11 +7087,13 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                          &req);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_ADDED,
-                             FILE_NOTIFY_CHANGE_FILE_NAME,
-                             dscp, lastNamep, NULL, TRUE);
-        if (!excl && code == CM_ERROR_EXISTS) {
+        if (code == 0) {
+           created = 1;
+           if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+               smb_NotifyChange(FILE_ACTION_ADDED,     
+                                FILE_NOTIFY_CHANGE_FILE_NAME,
+                                dscp, lastNamep, NULL, TRUE);
+       } else if (!excl && code == CM_ERROR_EXISTS) {
             /* not an exclusive create, and someone else tried
              * creating it already, then we open it anyway.  We
              * don't bother retrying after this, since if this next
@@ -6951,6 +7138,10 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* always create it open for read/write */
     fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
 
+    /* remember that the file was newly created */
+    if (created)
+       fidp->flags |= SMB_FID_CREATED;
+
     /* save a pointer to the vnode */
     fidp->scp = scp;
     /* and the user */
@@ -6971,6 +7162,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
+    osi_hyper_t new_offset;
     long offset;
     int whence;
     unsigned short fd;
@@ -7000,30 +7192,37 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
     lock_ReleaseMutex(&fidp->mx);
        
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
     lock_ObtainMutex(&scp->mx);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code == 0) {
         if (whence == 1) {
             /* offset from current offset */
-            offset += fidp->offset;
+            new_offset = LargeIntegerAdd(fidp->offset,
+                                         ConvertLongToLargeInteger(offset));
         }
         else if (whence == 2) {
             /* offset from current EOF */
-            offset += scp->length.LowPart;
+            new_offset = LargeIntegerAdd(scp->length,
+                                         ConvertLongToLargeInteger(offset));
+        } else {
+            new_offset = ConvertLongToLargeInteger(offset);
         }
-        fidp->offset = offset;
-        smb_SetSMBParm(outp, 0, offset & 0xffff);
-        smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
+
+        fidp->offset = new_offset;
+        smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
+        smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
         smb_SetSMBDataLength(outp, 0);
     }
     lock_ReleaseMutex(&scp->mx);
-    lock_ReleaseMutex(&fidp->mx);
     smb_ReleaseFID(fidp);
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     return code;
 }
@@ -7281,25 +7480,6 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
         smb_SendPacket(vcp, outp);
     thrd_Decrement(&ongoingOps);
 
-    if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
-        if (active_vcp != vcp) {
-            if (active_vcp) {
-                osi_Log2(smb_logp,
-                      "Replacing active_vcp %x with %x", active_vcp, vcp);
-                smb_ReleaseVC(active_vcp);
-            }
-            smb_HoldVC(vcp);
-           lock_ObtainWrite(&smb_globalLock);
-            active_vcp = vcp;
-           lock_ReleaseWrite(&smb_globalLock);
-        }
-        last_msg_time = GetTickCount();
-    } else if (active_vcp == vcp) {    /* the vcp is dead */
-        smb_ReleaseVC(active_vcp);
-       lock_ObtainWrite(&smb_globalLock);
-        active_vcp = NULL;
-       lock_ReleaseWrite(&smb_globalLock);
-    }
     return;
 }
 
@@ -7516,6 +7696,9 @@ void smb_Server(VOID *parmp)
            smb_ReleaseVC(vcp);
            vcp = NULL;
        }
+
+       smb_ResetServerPriority();
+
         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
                                                  FALSE, INFINITE);
 
@@ -7591,19 +7774,21 @@ void smb_Server(VOID *parmp)
             /* Client closed session */
             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
             if (vcp) {
-               lock_ObtainWrite(&smb_globalLock);
+               lock_ObtainMutex(&vcp->mx);
                if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
                              vcp, vcp->usersp);
-                   lock_ObtainMutex(&vcp->mx);
                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseMutex(&vcp->mx);
+                   lock_ObtainWrite(&smb_globalLock);
+                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseWrite(&smb_globalLock);
                    smb_CleanupDeadVC(vcp);
                    smb_ReleaseVC(vcp);
                    vcp = NULL;
-                }
+                } else {
+                   lock_ReleaseMutex(&vcp->mx);
+               }
             }
             goto doneWithNCB;
 
@@ -7632,28 +7817,33 @@ void smb_Server(VOID *parmp)
         default:
             /* A weird error code.  Log it, sleep, and continue. */
             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
+           if (vcp) 
+               lock_ObtainMutex(&vcp->mx);
             if (vcp && vcp->errorCount++ > 3) {
                 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
-               lock_ObtainWrite(&smb_globalLock);
                if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
                    osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
                             vcp, vcp->usersp);
-                   lock_ObtainMutex(&vcp->mx);
                    vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseMutex(&vcp->mx);
+                   lock_ObtainWrite(&smb_globalLock);
+                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseWrite(&smb_globalLock);
                    smb_CleanupDeadVC(vcp);
                    smb_ReleaseVC(vcp);
                    vcp = NULL;
-               }
+               } else {
+                   lock_ReleaseMutex(&vcp->mx);
+               }
                goto doneWithNCB;
             }
             else {
+               if (vcp)
+                   lock_ReleaseMutex(&vcp->mx);
                 thrd_Sleep(1000);
-                thrd_SetEvent(SessionEvents[idx_session]);
+               thrd_SetEvent(SessionEvents[idx_session]);
             }
-            continue;
+           continue;
         }
 
         /* Success, so now dispatch on all the data in the packet */
@@ -7667,6 +7857,8 @@ void smb_Server(VOID *parmp)
          * then we are in big trouble. This means either :
          *   a) we have the wrong NCB.
          *   b) Netbios screwed up the call.
+        *   c) The VC was already marked dead before we were able to
+        *      process the call
          * Obviously this implies that 
          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
          *   lanas[idx_session] != ncbp->ncb_lana_num )
@@ -7681,7 +7873,7 @@ void smb_Server(VOID *parmp)
                      ncbp->ncb_lana_num);
 
             /* Also log in the trace log. */
-            osi_Log4(smb_logp, "Server: BAD VCP!"
+            osi_Log4(smb_logp, "Server: VCP does not exist!"
                       "LSNs[idx_session]=[%d],"
                       "lanas[idx_session]=[%d],"
                       "ncbp->ncb_lsn=[%d],"
@@ -7697,6 +7889,8 @@ void smb_Server(VOID *parmp)
             continue;
         }
 
+       smb_SetRequestStartTime();
+
         vcp->errorCount = 0;
         bufp = (struct smb_packet *) ncbp->ncb_buffer;
 #ifdef DJGPP
@@ -8050,9 +8244,18 @@ void smb_Listener(void *parmp)
             smb_FreePacket(outp);
 
            lock_ObtainMutex(&vcp->mx);
-           vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-           lock_ReleaseMutex(&vcp->mx);
-           smb_CleanupDeadVC(vcp);
+           if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+               osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
+                         vcp, vcp->usersp);
+               vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+               lock_ReleaseMutex(&vcp->mx);
+               lock_ObtainWrite(&smb_globalLock);
+               dead_sessions[vcp->session] = TRUE;
+               lock_ReleaseWrite(&smb_globalLock);
+               smb_CleanupDeadVC(vcp);
+           } else {
+               lock_ReleaseMutex(&vcp->mx);
+           }
         } else {
             /* assert that we do not exceed the maximum number of sessions or NCBs.
              * we should probably want to wait for a session to be freed in case
@@ -8291,6 +8494,8 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     EVENT_HANDLE retHandle;
     char eventName[MAX_PATH];
 
+    smb_TlsRequestSlot = TlsAlloc();
+
 #ifndef DJGPP
     smb_MBfunc = aMBfunc;
 #endif /* DJGPP */
@@ -8467,6 +8672,8 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
+    smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
+    smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;       /* both are same */
     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
@@ -8782,7 +8989,11 @@ void smb_Shutdown(void)
         smb_fid_t *fidp;
         smb_tid_t *tidp;
      
-        for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+       for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
             if (fidp->scp != NULL) {
                 cm_scache_t * scp;
@@ -8810,6 +9021,8 @@ void smb_Shutdown(void)
         }
     }
     lock_ReleaseWrite(&smb_rctLock);
+
+    TlsFree(smb_TlsRequestSlot);
 }
 
 /* Get the UNC \\<servername>\<sharename> prefix. */
@@ -8885,7 +9098,7 @@ void smb_LogPacket(smb_packet_t *packet)
 
         *cp = 0;
 
-        osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
+        osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
     }
 
     osi_Log0(smb_logp, "*** End SMB packet dump ***");