/* 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)
{
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);
#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),
/* 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);
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 *)
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)
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;
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++;
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;
}
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;
void smb_ReleaseFID(smb_fid_t *fidp)
{
cm_scache_t *scp;
+ cm_user_t *userp;
smb_vc_t *vcp = NULL;
smb_ioctl_t *ioctlp;
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);
/* now release the scache structure */
if (scp)
cm_ReleaseSCache(scp);
+
+ if (userp)
+ cm_ReleaseUser(userp);
}
/*
/* 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;
*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);
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);
| 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;
}
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,
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);
/* 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);
case NRC_SCLOSED:
case NRC_SNUMOUT:
+ case NRC_SABORT:
/* Client closed session */
dead_sessions[idx_session] = TRUE;
if (vcp)
dead_vcp = vcp;
vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
}
+
+ smb_CleanupDeadVC(vcp);
+
if (vcp->justLoggedOut) {
loggedOut = 1;
loggedOutTime = vcp->logoffTime;