windows-byte-range-locking-20060108
authorAsanka Herath <asanka@secure-endpoints.com>
Mon, 9 Jan 2006 04:43:36 +0000 (04:43 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Mon, 9 Jan 2006 04:43:36 +0000 (04:43 +0000)
When SMB sessions are prematurely terminated as part of the tear down
of the virtual circuit we must clean up any remaining file handles,
tree connections, and user sessions.

src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb.h
src/WINNT/afsd/smb3.c

index 6294cf2..db966df 100644 (file)
@@ -75,7 +75,10 @@ typedef struct cm_file_lock {
 #define CM_FILELOCK_FLAG_WAITLOCK        0x04
 #define CM_FILELOCK_FLAG_WAITUNLOCK      0x0C
 
-/* the following is only to be used for locks on non-RO volumes */
+/* the following is used to indicate that there are no server side
+   locks associated with this lock.  This is true for locks obtained
+   against files in RO volumes as well as files residing on servers
+   that disable client side byte range locking. */
 #define CM_FILELOCK_FLAG_CLIENTONLY      0x10
 
 #define CM_FLSHARE_OFFSET_HIGH           0x01000000
index 5fdffad..91219c1 100644 (file)
@@ -3087,7 +3087,13 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
 /* unsafe */
 #define CONTAINS_RANGE(r1,r2) (((r2).offset+(r2).length) <= ((r1).offset+(r1).length) && (r1).offset <= (r2).offset)
 
-#define SERVERLOCKS_ENABLED(scp) (!((scp)->flags & CM_SCACHEFLAG_RO) && cm_enableServerLocks)
+#if defined(VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS) && !defined(LOCK_TESTING)
+#define SCP_SUPPORTS_BRLOCKS(scp) ((scp)->cbServerp && ((scp)->cbServerp->capabilities & VICED_CAPABILITY_USE_BYTE_RANGE_LOCKS))
+#else
+#define SCP_SUPPORTS_BRLOCKS(scp) (1)
+#endif
+
+#define SERVERLOCKS_ENABLED(scp) (!((scp)->flags & CM_SCACHEFLAG_RO) && cm_enableServerLocks && SCP_SUPPORTS_BRLOCKS(scp))
 
 static void cm_LockRangeSubtract(cm_range_t * pos, const cm_range_t * neg)
 {
@@ -3614,8 +3620,11 @@ long cm_UnlockByKey(cm_scache_t * scp,
     struct rx_connection * callp;
     int n_unlocks = 0;
 
-    osi_Log3(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x",
-             scp, (unsigned long)(key >> 32), (unsigned long)(key & 0xffffffff));
+    osi_Log4(afsd_logp, "cm_UnlockByKey scp 0x%p key 0x%x:%x flags=0x%x",
+             scp,
+             (unsigned long)(key >> 32),
+             (unsigned long)(key & 0xffffffff),
+             flags);
 
     lock_ObtainWrite(&cm_scacheLock);
 
@@ -3627,7 +3636,9 @@ long cm_UnlockByKey(cm_scache_t * scp,
 
 #ifdef DEBUG
         osi_Log4(afsd_logp, "   Checking lock[0x%x] range[%d,+%d] type[%d]",
-                fileLock, (unsigned long) fileLock->range.offset, (unsigned long) fileLock->range.length,
+                 fileLock,
+                 (unsigned long) fileLock->range.offset,
+                 (unsigned long) fileLock->range.length,
                 fileLock->lockType);
         osi_Log3(afsd_logp, "     key[0x%x:%x] flags[0x%x]",
                  (unsigned long)(fileLock->key >> 32),
@@ -4160,7 +4171,7 @@ void cm_CheckLocks()
 
             /* Server locks must have been enabled for us to have
                received an active non-client-only lock. */
-            //osi_assert(cm_enableServerLocks);
+            osi_assert(cm_enableServerLocks);
 
             scp = fileLock->scp;
             osi_assert(scp != NULL);
@@ -4381,7 +4392,6 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
     if(IS_LOCK_WAITUNLOCK(oldFileLock)) {
 
         /* check if the conflicting locks have dissappeared already */
-
         for(q = scp->fileLocksH; q; q = osi_QNext(q)) {
 
             fileLock = (cm_file_lock_t *)
@@ -4546,9 +4556,16 @@ long cm_RetryLock(cm_file_lock_t *oldFileLock, int client_is_dead)
 
 cm_key_t cm_GenerateKey(unsigned int session_id, unsigned long process_id, unsigned int file_id)
 {
-    return (((cm_key_t) process_id) << 32) |
-        (((cm_key_t) session_id) << 16) |
-        (((cm_key_t) file_id));
+#ifdef DEBUG
+    osi_assert((process_id & 0xffffffff) == process_id);
+    osi_assert((session_id & 0xffff) == session_id);
+    osi_assert((file_id & 0xffff) == file_id);
+#endif
+
+    return 
+        (((cm_key_t) (process_id & 0xffffffff)) << 32) |
+        (((cm_key_t) (session_id & 0xffff)) << 16) |
+        (((cm_key_t) (file_id & 0xffff)));
 }
 
 static int cm_KeyEquals(cm_key_t k1, cm_key_t k2, int flags)
index bb2c2aa..2d9de36 100644 (file)
@@ -12,6 +12,8 @@
 
 extern unsigned int cm_mountRootGen;
 
+extern int cm_enableServerLocks;
+
 /* parms for attribute setting call */
 typedef struct cm_attr {
        int mask;
@@ -150,7 +152,7 @@ extern long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
        int allowWait, cm_user_t *userp, cm_req_t *reqp,
        cm_file_lock_t **lockpp);
 
-#define CM_UNLOCK_BY_FID 1
+#define CM_UNLOCK_BY_FID       0x0001
 
 extern long cm_UnlockByKey(cm_scache_t * scp,
         cm_key_t key,
index 9936e4f..20a9254 100644 (file)
@@ -922,6 +922,90 @@ void smb_HoldVC(smb_vc_t *vcp)
     lock_ReleaseWrite(&smb_rctLock);
 }       
 
+void smb_CleanupDeadVC(smb_vc_t *vcp)
+{
+    smb_fid_t *fidpIter;
+    smb_fid_t *fidpNext;
+    smb_fid_t *fidp;
+    unsigned short fid;
+    smb_tid_t *tidpIter;
+    smb_tid_t *tidpNext;
+    smb_tid_t *tidp;
+    unsigned short tid;
+    smb_user_t *userpIter;
+    smb_user_t *userpNext;
+    smb_user_t *userp;
+    unsigned short uid;
+
+    osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
+
+    lock_ObtainRead(&smb_rctLock);
+    for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
+        fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
+
+        if (fidpIter->flags & SMB_FID_DELETE)
+            continue;
+
+        fid = fidpIter->fid;
+       osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
+        lock_ReleaseRead(&smb_rctLock);
+
+        fidp = smb_FindFID(vcp, fid, 0);
+        osi_assert(fidp);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+
+        lock_ObtainRead(&smb_rctLock);
+    }
+
+    for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
+       tidpNext = tidpIter->nextp;
+       if (tidpIter->flags & SMB_TIDFLAG_DELETE)
+           continue;
+
+       tid = tidpIter->tid;
+       osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
+       lock_ReleaseRead(&smb_rctLock);
+
+       tidp = smb_FindTID(vcp, tid, 0);
+       osi_assert(tidp);
+
+       lock_ObtainMutex(&tidp->mx);
+       tidp->flags |= SMB_TIDFLAG_DELETE;
+       lock_ReleaseMutex(&tidp->mx);
+
+       smb_ReleaseTID(tidp);
+
+       lock_ObtainRead(&smb_rctLock);
+    }
+
+    for (userpIter = vcp->usersp; userpIter; userpIter = userpNext) {
+       userpNext = userpIter->nextp;
+
+       if (userpIter->flags & SMB_USERFLAG_DELETE)
+           continue;
+
+       uid = userpIter->userID;
+       osi_Log2(smb_logp, "  Cleanup UID %d (userp=0x%x)", uid, userpIter);
+       lock_ReleaseRead(&smb_rctLock);
+
+       userp = smb_FindUID(vcp, uid, 0);
+       osi_assert(userp);
+
+       lock_ObtainMutex(&userp->mx);
+       userp->flags |= SMB_USERFLAG_DELETE;
+       lock_ReleaseMutex(&userp->mx);
+
+       smb_ReleaseUID(userp);
+
+       lock_ObtainRead(&smb_rctLock);
+    }
+
+    lock_ReleaseRead(&smb_rctLock);
+
+    osi_Log0(smb_logp, "Done cleaning up dead vcp");
+}
+
 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
 {
     smb_tid_t *tidp;
@@ -1177,8 +1261,11 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
         if (fid == fidp->fid) {
             if (newFid) {
                 fid++;
-                if (fid == 0) 
+                if (fid == 0) {
+                    osi_Log1(smb_logp,
+                             "New FID number wraps on vcp 0x%x", vcp);
                     fid = 1;
+                }
                 goto retry;
             }
             fidp->refCount++;
@@ -1195,8 +1282,10 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
             thrd_CloseHandle(event);
             fid++;
-            if (fid == 0)
+            if (fid == 0) {
+                osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
                 fid = 1;
+            }
             goto retry;
         }
 
@@ -1212,10 +1301,13 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
         fidp->raw_write_event = event;
         if (newFid) {
             vcp->fidCounter = fid+1;
-            if (vcp->fidCounter == 0) 
+            if (vcp->fidCounter == 0) {
+                osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
+                         vcp);
                 vcp->fidCounter = 1;
         }
     }
+    }
 
     lock_ReleaseWrite(&smb_rctLock);
     return fidp;
@@ -1224,6 +1316,7 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
 void smb_ReleaseFID(smb_fid_t *fidp)
 {
     cm_scache_t *scp;
+    cm_user_t *userp;
     smb_vc_t *vcp = NULL;
     smb_ioctl_t *ioctlp;
 
@@ -1231,13 +1324,16 @@ void smb_ReleaseFID(smb_fid_t *fidp)
         return;
 
     scp = NULL;
+    userp = NULL;
     lock_ObtainWrite(&smb_rctLock);
     osi_assert(fidp->refCount-- > 0);
     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
         vcp = fidp->vcp;
-        fidp->vcp = 0;
+        fidp->vcp = NULL;
         scp = fidp->scp;    /* release after lock is released */
-        fidp->scp = 0;
+        fidp->scp = NULL;
+        userp = fidp->userp;
+        fidp->userp = NULL;
 
         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
         thrd_CloseHandle(fidp->raw_write_event);
@@ -1263,6 +1359,9 @@ void smb_ReleaseFID(smb_fid_t *fidp)
     /* now release the scache structure */
     if (scp) 
         cm_ReleaseSCache(scp);
+
+    if (userp)
+        cm_ReleaseUser(userp);
 }       
 
 /*
@@ -4582,6 +4681,9 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    /* and the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
 
     if ((share & 0xf) == 0)
         fidp->flags |= SMB_FID_OPENREAD;
@@ -5393,29 +5495,25 @@ void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
         *newPathp = strdup(pathp);
 }
 
-long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
-{
-    unsigned short fid;
-    smb_fid_t *fidp;
-    cm_user_t *userp;
-    afs_uint32 dosTime;
+long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
+                  afs_uint32 dosTime) {
     long code = 0;
     cm_req_t req;
 
-    cm_InitReq(&req);
-
-    fid = smb_GetSMBParm(inp, 0);
-    dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
-
-    osi_Log1(smb_logp, "SMB close fid %d", fid);
+    osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
+             fidp, fidp->fid, vcp);
 
-    fid = smb_ChainFID(fid, inp);
-    fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp) {
+    if (!userp) {
+        if (!fidp->userp) {
+            osi_Log0(smb_logp, "  No user specified.  Not closing fid");
         return CM_ERROR_BADFD;
     }
         
-    userp = smb_GetUser(vcp, inp);
+        userp = fidp->userp;    /* no hold required since fidp is held
+                                   throughout the function */
+    }
+
+    cm_InitReq(&req);
 
     lock_ObtainMutex(&fidp->mx);
 
@@ -5447,12 +5545,12 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
         fidp->scp->fileType == CM_SCACHETYPE_FILE) {
         cm_key_t key;
-        unsigned pid;
         cm_scache_t * scp;
         long tcode;
 
-        pid = ((smb_t *) inp)->pid;
-        key = cm_GenerateKey(vcp->vcID, pid, fid);
+        /* 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);
@@ -5463,7 +5561,8 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                           | CM_SCACHESYNC_LOCK);
 
         if (tcode) {
-            osi_Log1(smb_logp, "smb CoreClose SyncOp failure code 0x%x", tcode);
+            osi_Log1(smb_logp,
+                     "smb CoreClose SyncOp failure code 0x%x", tcode);
             goto post_syncopdone;
         }
 
@@ -5489,9 +5588,7 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 smb_NotifyChange(FILE_ACTION_REMOVED,
                                  FILE_NOTIFY_CHANGE_DIR_NAME,
                                  dscp, fullPathp, NULL, TRUE);
-        }
-        else 
-        {
+        } else {
             code = cm_Unlink(dscp, fullPathp, userp, &req);
             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_REMOVED,
@@ -5505,9 +5602,38 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (fidp->flags & SMB_FID_NTOPEN) {
         cm_ReleaseSCache(fidp->NTopen_dscp);
         free(fidp->NTopen_pathp);
+        fidp->NTopen_pathp = NULL;
     }
-    if (fidp->NTopen_wholepathp)
+    if (fidp->NTopen_wholepathp) {
         free(fidp->NTopen_wholepathp);
+        fidp->NTopen_wholepathp = NULL;
+    }
+
+    return code;
+}
+
+long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+    unsigned short fid;
+    smb_fid_t *fidp;
+    cm_user_t *userp;
+    long code = 0;
+    afs_uint32 dosTime;
+
+    fid = smb_GetSMBParm(inp, 0);
+    dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
+
+    osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
+
+    fid = smb_ChainFID(fid, inp);
+    fidp = smb_FindFID(vcp, fid, 0);
+    if (!fidp) {
+        return CM_ERROR_BADFD;
+    }
+        
+    userp = smb_GetUser(vcp, inp);
+
+    code = smb_CloseFID(vcp, fidp, userp, dosTime);
     
     smb_ReleaseFID(fidp);
     cm_ReleaseUser(userp);
@@ -6625,6 +6751,9 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    /* and the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
         
     /* always create it open for read/write */
     fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
@@ -7369,6 +7498,7 @@ void smb_Server(VOID *parmp)
 
         case NRC_SCLOSED:
         case NRC_SNUMOUT:
+       case NRC_SABORT:
             /* Client closed session */
             dead_sessions[idx_session] = TRUE;
             if (vcp)
@@ -7396,6 +7526,9 @@ void smb_Server(VOID *parmp)
                     dead_vcp = vcp;
                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
                 }
+
+                smb_CleanupDeadVC(vcp);
+
                 if (vcp->justLoggedOut) {
                     loggedOut = 1;
                     loggedOutTime = vcp->logoffTime;
index 12ce605..02a2a75 100644 (file)
@@ -230,7 +230,7 @@ typedef struct smb_user {
     unsigned long refCount;            /* ref count */
     long flags;                                /* flags; locked by mx */
     osi_mutex_t mx;
-    long userID;                       /* the session identifier */
+    unsigned short userID;             /* the session identifier */
     struct smb_vc *vcp;                        /* back ptr to virtual circuit */
     struct smb_username *unp;           /* user name struct */
 } smb_user_t;
@@ -315,6 +315,10 @@ typedef struct smb_fid {
     unsigned short fid;                        /* the file ID */
     struct smb_vc *vcp;                        /* back ptr */
     struct cm_scache *scp;             /* scache of open file */
+    struct cm_user *userp;              /* user that opened the file
+                                           originally (used to close
+                                           the file if session is
+                                           terminated) */
     long offset;                       /* our file pointer */
     smb_ioctl_t *ioctlp;               /* ptr to ioctl structure */
                                        /* Under NT, we may need to know the
@@ -511,6 +515,9 @@ extern smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags);
 
 extern void smb_ReleaseFID(smb_fid_t *fidp);
 
+extern long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
+                         afs_uint32 dosTime);
+
 extern int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName, char **pathNamep);
 
 extern int smb_FindShareCSCPolicy(char *shareName);
index 6b79a09..0436732 100644 (file)
@@ -842,7 +842,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (uidp) {   /* already there, so don't create a new one */
         unp = uidp->unp;
         userp = unp->userp;
-        newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
+        newUid = uidp->userID;
         osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
         smb_ReleaseUID(uidp);
     }
@@ -2337,6 +2337,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
        
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    /* and the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
         
     /* compute open mode */
     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
@@ -4715,6 +4718,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    /* also the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
         
     /* compute open mode */
     if (openMode != 1) 
@@ -5904,6 +5910,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
     osi_assert(fidp);
 
+    /* save a reference to the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
+
     /* If we are restricting sharing, we should do so with a suitable
        share lock. */
     if (scp->fileType == CM_SCACHETYPE_FILE &&
@@ -6492,6 +6502,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
     osi_assert(fidp);
 
+    /* save a reference to the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
+
     /* If we are restricting sharing, we should do so with a suitable
        share lock. */
     if (scp->fileType == CM_SCACHETYPE_FILE &&