callback-deadlock-20040819
[openafs.git] / src / WINNT / afsd / cm_callback.c
index ddc9af0..950a2db 100644 (file)
@@ -90,33 +90,34 @@ void cm_RecordRacingRevoke(cm_fid_t *fidp, long cancelFlags)
 
 /*
  * When we lose a callback, may have to send change notification replies.
+ * Do not call with a lock on the scp.
  */
 void cm_CallbackNotifyChange(cm_scache_t *scp)
 {
     osi_Log2(afsd_logp, "CallbackNotifyChange FileType %d Flags %lX",
               scp->fileType, scp->flags);
 
-       if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
-               if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
-                       smb_NotifyChange(0,
-                        FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
-                        scp, NULL, NULL, TRUE);
-       } else {
-               cm_fid_t tfid;
-               cm_scache_t *dscp;
-
-               tfid.cell = scp->fid.cell;
-               tfid.volume = scp->fid.volume;
-               tfid.vnode = scp->parentVnode;
-               tfid.unique = scp->parentUnique;
-               dscp = cm_FindSCache(&tfid);
-               if (dscp &&
-                       dscp->flags & CM_SCACHEFLAG_ANYWATCH)
-                       smb_NotifyChange(0,
-                        FILE_NOTIFY_GENERIC_FILE_FILTER,
-                        dscp, NULL, NULL, TRUE);
-               if (dscp) cm_ReleaseSCache(dscp);
-       }
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+        if (scp->flags & CM_SCACHEFLAG_ANYWATCH)
+            smb_NotifyChange(0,
+                             FILE_NOTIFY_GENERIC_DIRECTORY_FILTER,
+                             scp, NULL, NULL, TRUE);
+    } else {
+        cm_fid_t tfid;
+        cm_scache_t *dscp;
+
+        tfid.cell = scp->fid.cell;
+        tfid.volume = scp->fid.volume;
+        tfid.vnode = scp->parentVnode;
+        tfid.unique = scp->parentUnique;
+        dscp = cm_FindSCache(&tfid);
+        if (dscp &&
+             dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+            smb_NotifyChange( 0,
+                              FILE_NOTIFY_GENERIC_FILE_FILTER,
+                              dscp,   NULL, NULL, TRUE);
+        if (dscp) cm_ReleaseSCache(dscp);
+    }
 }
 
 /* called with no locks held for every file ID that is revoked directly by
@@ -635,11 +636,13 @@ int cm_HaveCallback(cm_scache_t *scp)
   int fdc, fgc;
 
     if (cm_freelanceEnabled && 
-        scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
-        scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {       // if it's something on /afs
-       if (!(scp->fid.vnode==0x1 && scp->fid.unique==0x1))     // if it's not root.afs
+         scp->fid.cell==AFS_FAKE_ROOT_CELL_ID && scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
+        /* if it's something on /afs */
+        if (!(scp->fid.vnode==0x1 && scp->fid.unique==0x1)) {
+            /* if it's not root.afs */
            return 1;
-       else {
+        }
+
            lock_ObtainMutex(&cm_Freelance_Lock);
            fdc = cm_fakeDirCallback;
            fgc = cm_fakeGettingCallback;
@@ -650,19 +653,21 @@ int cm_HaveCallback(cm_scache_t *scp)
            } else if (fdc==2 && !fgc) {        // we're in good shape
                if (cm_getLocalMountPointChange()) {    // check for changes
                    cm_clearLocalMountPointChange(); // clear the changefile
+            lock_ReleaseMutex(&scp->mx);      // this is re-locked in reInitLocalMountPoints
                    cm_reInitLocalMountPoints();        // start reinit
+            lock_ObtainMutex(&scp->mx);      // now get the lock back 
                    return 0;
                }
                return 1;                       // no change
            }
            return 0;
        }
-    }
 #endif
 
     if (scp->cbServerp != NULL)
        return 1;
-    else return 0;
+    else 
+        return 0;
 }
 
 /* need to detect a broken callback that races with our obtaining a callback.
@@ -706,6 +711,7 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
        cm_racingRevokes_t *revp;               /* where we are */
        cm_racingRevokes_t *nrevp;              /* where we'll be next */
         int freeFlag;
+    cm_server_t * serverp = 0;
 
        lock_ObtainWrite(&cm_callbackLock);
        if (flags & CM_CALLBACK_MAINTAINCOUNT) {
@@ -714,13 +720,23 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
        else {
                osi_assert(cm_activeCallbackGrantingCalls-- > 0);
        }
-        if (cm_activeCallbackGrantingCalls == 0) freeFlag = 1;
-        else freeFlag = 0;
+    if (cm_activeCallbackGrantingCalls == 0) 
+        freeFlag = 1;
+    else 
+        freeFlag = 0;
 
        /* record the callback; we'll clear it below if we really lose it */
+    if (cbrp) {
        if (scp) {
+            if (scp->cbServerp != cbrp->serverp) {
+                serverp = scp->cbServerp;
+            }
                scp->cbServerp = cbrp->serverp;
                scp->cbExpires = cbrp->startTime + cbp->ExpirationTime;
+        } else {
+            serverp = cbrp->serverp;
+        }
+        cbrp->serverp = NULL;
        }
 
        /* a callback was actually revoked during our granting call, so
@@ -735,7 +751,7 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
                  * callback-granting call, and if this fid is the right fid,
                  * then clear the callback.
                  */
-                if (scp && cbrp->callbackCount != cm_callbackCount
+        if (scp && cbrp && cbrp->callbackCount != cm_callbackCount
                                && revp->callbackCount > cbrp->callbackCount
              && (( scp->fid.volume == revp->fid.volume &&
                                  scp->fid.vnode == revp->fid.vnode &&
@@ -767,6 +783,12 @@ void cm_EndCallbackGrantingCall(cm_scache_t *scp, cm_callbackRequest_t *cbrp,
        if (freeFlag) cm_racingRevokesp = NULL;
 
        lock_ReleaseWrite(&cm_callbackLock);
+
+    if ( serverp ) {
+        lock_ObtainWrite(&cm_serverLock);
+        cm_FreeServer(serverp);
+        lock_ReleaseWrite(&cm_serverLock);
+    }
 }
 
 /* if flags is 1, we want to force the code to make one call, anyway.
@@ -797,10 +819,11 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
              scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
              scp->fid.unique==0x1 &&
              scp->fid.vnode==0x1) {
+            
             // Start by indicating that we're in the process
             // of fetching the callback
-
             lock_ObtainMutex(&cm_Freelance_Lock);
+            osi_Log0(afsd_logp,"cm_getGetCallback fakeGettingCallback=1");
             cm_fakeGettingCallback = 1;
             lock_ReleaseMutex(&cm_Freelance_Lock);
 
@@ -809,8 +832,11 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
 
             // Indicate that the callback is not done
             lock_ObtainMutex(&cm_Freelance_Lock);
+            osi_Log0(afsd_logp,"cm_getGetCallback fakeDirCallback=2");
             cm_fakeDirCallback = 2;
+
             // Indicate that we're no longer fetching the callback
+            osi_Log0(afsd_logp,"cm_getGetCallback fakeGettingCallback=0");
             cm_fakeGettingCallback = 0;
             lock_ReleaseMutex(&cm_Freelance_Lock);
 
@@ -859,7 +885,7 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
             cm_MergeStatus(scp, &afsStatus, &volSync, userp, 0);
                }   
         else
-            cm_EndCallbackGrantingCall(NULL, NULL, NULL, 0);
+            cm_EndCallbackGrantingCall(NULL, &cbr, NULL, 0);
 
         /* now check to see if we got an error */
         if (code) return code;
@@ -869,29 +895,30 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
 /* called periodically by cm_daemon to shut down use of expired callbacks */
 void cm_CheckCBExpiration(void)
 {
-       int i;
-        cm_scache_t *scp;
-        long now;
+    int i;
+    cm_scache_t *scp;
+    long now;
         
     osi_Log0(afsd_logp, "CheckCBExpiration");
 
-       now = osi_Time();
-       lock_ObtainWrite(&cm_scacheLock);
-        for(i=0; i<cm_hashTableSize; i++) {
-               for(scp = cm_hashTablep[i]; scp; scp=scp->nextp) {
-                       scp->refCount++;
-                       lock_ReleaseWrite(&cm_scacheLock);
-                       lock_ObtainMutex(&scp->mx);
-                       if (scp->cbServerp && now > scp->cbExpires) {
-                osi_Log1(afsd_logp, "Discarding SCache scp %x", scp);
-                               cm_DiscardSCache(scp);
-                        }
-                       lock_ReleaseMutex(&scp->mx);
-                       lock_ObtainWrite(&cm_scacheLock);
-                        osi_assert(scp->refCount-- > 0);
-                }
+    now = osi_Time();
+    lock_ObtainWrite(&cm_scacheLock);
+    for(i=0; i<cm_hashTableSize; i++) {
+        for(scp = cm_hashTablep[i]; scp; scp=scp->nextp) {
+            scp->refCount++;
+            lock_ReleaseWrite(&cm_scacheLock);
+            if (scp->cbExpires > 0 && (scp->cbServerp == NULL || now > scp->cbExpires)) {
+                osi_Log1(afsd_logp, "Callback Expiration Discarding SCache scp %x", scp);
+                cm_CallbackNotifyChange(scp);
+                lock_ObtainMutex(&scp->mx);
+                cm_DiscardSCache(scp);
+                lock_ReleaseMutex(&scp->mx);
+            }
+            lock_ObtainWrite(&cm_scacheLock);
+            osi_assert(scp->refCount-- > 0);
         }
-        lock_ReleaseWrite(&cm_scacheLock);
+    }
+    lock_ReleaseWrite(&cm_scacheLock);
 }
 
 /* debug interface: not implemented */