From 78c40badbd8c65d82f6c384fdff8056c03100b67 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Mon, 9 Jan 2006 04:43:36 +0000 Subject: [PATCH] windows-byte-range-locking-20060108 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 | 5 +- src/WINNT/afsd/cm_vnodeops.c | 35 +++++-- src/WINNT/afsd/cm_vnodeops.h | 4 +- src/WINNT/afsd/smb.c | 191 +++++++++++++++++++++++++++++------ src/WINNT/afsd/smb.h | 9 +- src/WINNT/afsd/smb3.c | 16 ++- 6 files changed, 218 insertions(+), 42 deletions(-) diff --git a/src/WINNT/afsd/cm_scache.h b/src/WINNT/afsd/cm_scache.h index 6294cf276..db966df0b 100644 --- a/src/WINNT/afsd/cm_scache.h +++ b/src/WINNT/afsd/cm_scache.h @@ -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 diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index 5fdffadf0..91219c16f 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -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) diff --git a/src/WINNT/afsd/cm_vnodeops.h b/src/WINNT/afsd/cm_vnodeops.h index bb2c2aadb..2d9de36aa 100644 --- a/src/WINNT/afsd/cm_vnodeops.h +++ b/src/WINNT/afsd/cm_vnodeops.h @@ -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, diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 9936e4f1a..20a925454 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -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; diff --git a/src/WINNT/afsd/smb.h b/src/WINNT/afsd/smb.h index 12ce60599..02a2a7566 100644 --- a/src/WINNT/afsd/smb.h +++ b/src/WINNT/afsd/smb.h @@ -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); diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index 6b79a09dc..043673280 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -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 && -- 2.39.5