viced-rewrite-breaklatercallbacks-20030218
[openafs.git] / src / viced / callback.c
index 7e43bfa..943e626 100644 (file)
@@ -120,7 +120,7 @@ RCSID("$Header$");
 #include <afs/ptclient.h>  /* need definition of prlist for host.h */
 #include "host.h"
 
-
+extern afsUUID FS_HostUUID;
 extern int hostCount;
 int ShowProblems = 1;
 
@@ -146,12 +146,15 @@ struct cbstruct {
 
 struct FileEntry {
     afs_uint32     vnode;      
-    afs_uint32         unique;
+    afs_uint32      unique;
     afs_uint32     volid;
     afs_uint32     fnext;
     afs_uint32     ncbs;
     afs_uint32     firstcb;
+    afs_uint32      status;
+    afs_uint32      spare;
 } *FE; /* Don't use FE[0] */
+#define FE_LATER 0x1
 
 struct CallBack {
     afs_uint32     cnext;              /* Next call back entry */
@@ -281,14 +284,15 @@ static int TAdd(register struct CallBack *cb, register afs_uint32 *thead);
 static int TDel(register struct CallBack *cb);
 static int HAdd(register struct CallBack *cb, register struct host *host);
 static int HDel(register struct CallBack *cb);
-static int CDel(struct CallBack *cb);
-static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp);
+static int CDel(struct CallBack *cb, int deletefe);
+static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp, int deletefe);
 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
 static int FDel(register struct FileEntry *fe);
 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead, int type, int locked);
 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas, struct AFSCBFids *afidp, struct host *xhost);
-static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms);
+static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms, int deletefe);
 static int MultiBreakVolumeCallBack(struct host *host, int isheld, struct VCBParams *parms);
+static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld, struct VCBParams *parms);
 static int lih_r(register struct host *host, register int held, register struct host *hostp);
 static int GetSomeSpace_r(struct host *hostp, int locked);
 
@@ -428,7 +432,7 @@ static int HDel(register struct CallBack *cb)
 /* N.B.  This one also deletes the CB, and also possibly parent FE, so
  * make sure that it is not on any other list before calling this
  * routine */
-static int CDel(struct CallBack *cb)
+static int CDel(struct CallBack *cb, int deletefe)
 {
     int cbi = cbtoi(cb);
     struct FileEntry *fe = itofe(cb->fhead);
@@ -444,7 +448,7 @@ static int CDel(struct CallBack *cb)
        ShutDown();
       }
     }
-    CDelPtr(fe, cbp);
+    CDelPtr(fe, cbp, deletefe);
     return 0;
 }
 
@@ -456,7 +460,7 @@ static int CDel(struct CallBack *cb)
 int Ccdelpt=0, CcdelB=0;
 
 static int CDelPtr(register struct FileEntry *fe, 
-       register afs_uint32 *cbp)
+       register afs_uint32 *cbp, int deletefe)
 {
     register struct CallBack *cb;
 
@@ -468,7 +472,7 @@ static int CDelPtr(register struct FileEntry *fe,
        CcdelB++;
     *cbp = cb->cnext;
     FreeCB(cb);
-    if (--fe->ncbs == 0)
+    if (deletefe && (--fe->ncbs == 0))
        FDel(fe);
     return 0;
 }
@@ -511,14 +515,21 @@ int InitCallBack(int nblks)
 {
     H_LOCK
     tfirst = CBtime(FT_ApproxTime());
-    /* N.B. FE's, CB's share same free list.  If the sizes of either change,
-      FE and CB will have to be separated.  The "-1", below, is because
+    /* N.B. The "-1", below, is because
       FE[0] and CB[0] are not used--and not allocated */
     FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
+    if (!FE) {
+       ViceLog(0, ("Failed malloc in InitCallBack\n"));
+       assert(0);
+    }
     cbstuff.nFEs = nblks;
     while (cbstuff.nFEs)
        FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
     CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
+    if (!CB) {
+       ViceLog(0, ("Failed malloc in InitCallBack\n"));
+       assert(0);
+    }
     cbstuff.nCBs = nblks;
     while (cbstuff.nCBs)
        FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
@@ -785,7 +796,7 @@ static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
                ViceLog(7, 
                  ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
                   afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
-                  afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), hp->port));
+                  afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), ntohs(hp->port)));
                }
 
                H_LOCK
@@ -837,7 +848,7 @@ int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
     char hoststr[16];
 
     ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
-              afs_inet_ntoa_r(xhost->host,hoststr), xhost->port, fid->Volume, fid->Vnode, 
+              afs_inet_ntoa_r(xhost->host,hoststr), ntohs(xhost->port), fid->Volume, fid->Vnode, 
               fid->Unique));
 
     H_LOCK
@@ -868,7 +879,7 @@ int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
          }
          else if (thishost->hostFlags & VENUSDOWN) {
            ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
-                      afs_inet_ntoa_r(thishost->host,hoststr), thishost->port));
+                      afs_inet_ntoa_r(thishost->host,hoststr), ntohs(thishost->port)));
            cb->status = CB_DELAYED;
          }
          else {
@@ -878,8 +889,8 @@ int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
            ncbas++;
            TDel(cb);
            HDel(cb);
-           CDel(cb); /* Usually first; so this delete */
-                     /* is reasonably inexpensive */
+           CDel(cb, 1); /* Usually first; so this delete 
+                           is reasonably inexpensive */
          }
        }
       }
@@ -927,14 +938,14 @@ int DeleteCallBack(struct host *host, AFSFid *fid)
     pcb = FindCBPtr(fe, host);
     if (!*pcb) {
        ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
-           afs_inet_ntoa_r(host->host,hoststr), host->port, fid->Volume, fid->Vnode, fid->Unique));
+           afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), fid->Volume, fid->Vnode, fid->Unique));
        h_Unlock_r(host);
        H_UNLOCK
        return 0;
     }
     HDel(itocb(*pcb));
     TDel(itocb(*pcb));
-    CDelPtr(fe, pcb);
+    CDelPtr(fe, pcb, 1);
     h_Unlock_r(host);
     H_UNLOCK
     return 0;
@@ -976,16 +987,7 @@ int DeleteFileCallBacks(AFSFid *fid)
 
 /* Delete (do not break) all call backs for host.  The host should be
  * locked. */
-int DeleteAllCallBacks(struct host *host)
-{
-    int retVal;
-    H_LOCK
-    retVal = DeleteAllCallBacks_r(host);
-    H_UNLOCK
-    return retVal;
-}
-
-int DeleteAllCallBacks_r(struct host *host)
+int DeleteAllCallBacks_r(struct host *host, int deletefe)
 {
     register struct CallBack *cb;
     register int cbi, first;
@@ -1000,7 +1002,7 @@ int DeleteAllCallBacks_r(struct host *host)
        cb = itocb(cbi);
        cbi = cb->hnext;
        TDel(cb);
-       CDel(cb);
+       CDel(cb, deletefe);
     } while (cbi != first);
     host->cblist = 0;
     return 0;
@@ -1020,8 +1022,6 @@ int BreakDelayedCallBacks(struct host *host)
     return retVal;
 }
 
-extern afsUUID FS_HostUUID;
-
 int BreakDelayedCallBacks_r(struct host *host)
 {
     struct AFSFid fids[AFSCBMAX];
@@ -1050,7 +1050,7 @@ int BreakDelayedCallBacks_r(struct host *host)
            if (ShowProblems) {
                ViceLog(0,
           ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
-                       afs_inet_ntoa_r(host->host,hoststr), host->port));
+                       afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
              }
            host->hostFlags |= VENUSDOWN;
        }
@@ -1080,7 +1080,7 @@ int BreakDelayedCallBacks_r(struct host *host)
                nfids++;
                HDel(cb);
                TDel(cb);
-               CDel(cb);
+               CDel(cb, 1);
            }
        } while (cbi && cbi != first && nfids < AFSCBMAX);
 
@@ -1095,13 +1095,13 @@ int BreakDelayedCallBacks_r(struct host *host)
            if (ShowProblems) {
                ViceLog(0,
             ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
-                   afs_inet_ntoa_r(host->host,hoststr), host->port));
+                   afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
            }
            for (i = 0; i<nfids; i++) {
                if (ShowProblems) {
                    ViceLog(0,
                    ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
-                              afs_inet_ntoa_r(host->host,hoststr), host->port, 
+                              afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), 
                               fids[i].Volume, fids[i].Vnode, fids[i].Unique));
                }
                /* used to do this:
@@ -1119,6 +1119,9 @@ int BreakDelayedCallBacks_r(struct host *host)
     }
 
     cbstuff.nbreakers--;
+    /* If we succeeded it's always ok to unset HFE_LATER */
+    if (!host->hostFlags & VENUSDOWN)
+       host->hostFlags &= ~HFE_LATER;
     return (host->hostFlags & VENUSDOWN);
 }
 
@@ -1127,7 +1130,7 @@ int BreakDelayedCallBacks_r(struct host *host)
 ** isheld is 1 if the host is held in BreakVolumeCallBacks
 */
 static int MultiBreakVolumeCallBack_r(struct host *host, 
-       int isheld, struct VCBParams *parms)
+       int isheld, struct VCBParams *parms, int deletefe)
 {
     char hoststr[16];
 
@@ -1143,14 +1146,16 @@ static int MultiBreakVolumeCallBack_r(struct host *host,
            return 0;      /* Release hold */
        }
        ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
-                afs_inet_ntoa_r(host->host,hoststr),host->port));
+                afs_inet_ntoa_r(host->host,hoststr),ntohs(host->port)));
        if (ShowProblems) {
            ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
-                   afs_inet_ntoa_r(host->host,hoststr), host->port));
+                   afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
        }
-       DeleteAllCallBacks_r(host); /* Delete all callback state rather than
-                                    attempting to selectively remember to
-                                    delete the volume callbacks later */
+       DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state 
+                                                rather than attempting to 
+                                                selectively remember to
+                                                delete the volume callbacks
+                                                later */
        host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
        h_Unlock_r(host);
        return 0; /* release hold */
@@ -1185,7 +1190,21 @@ static int MultiBreakVolumeCallBack(struct host *host, int isheld,
 {
     int retval;
     H_LOCK
-    retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
+    retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
+    H_UNLOCK
+    return retval;
+}
+
+/*
+** isheld is 0 if the host is held in h_Enumerate
+** isheld is 1 if the host is held in BreakVolumeCallBacks
+*/
+static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld, 
+       struct VCBParams *parms)
+{
+    int retval;
+    H_LOCK
+    retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
     H_UNLOCK
     return retval;
 }
@@ -1267,6 +1286,144 @@ int BreakVolumeCallBacks(afs_uint32 volume)
     return 0;
 }
 
+#ifdef AFS_PTHREAD_ENV
+extern pthread_cond_t fsync_cond;
+#else
+extern char fsync_wait[];
+#endif
+
+int BreakVolumeCallBacksLater(afs_uint32 volume)
+{
+    int hash;
+    afs_int32 *feip;
+    struct FileEntry *fe;
+    struct CallBack *cb;
+    struct host *host;
+    int found = 0;
+
+    ViceLog(25, ("Setting later on volume %d\n", volume));
+    H_LOCK
+    for (hash=0; hash<VHASH; hash++) {
+       for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
+           if (fe->volid == volume) {
+               register struct CallBack *cbnext;
+                for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
+                   host = h_itoh(cb->hhead);
+                   host->hostFlags |= HFE_LATER;
+                   cb->status = CB_DELAYED;
+                    cbnext = itocb(cb->cnext);
+                }
+               FSYNC_LOCK
+               fe->status |= FE_LATER;
+               FSYNC_UNLOCK
+               found++;
+           }
+           feip = &fe->fnext;
+       }
+    }
+    H_UNLOCK
+
+    if (!found) {
+       /* didn't find any callbacks, so return right away. */
+       return 0;
+    }
+
+    ViceLog(25, ("Fsync thread wakeup\n"));
+#ifdef AFS_PTHREAD_ENV
+    assert(pthread_cond_broadcast(&fsync_cond) == 0);
+#else
+    LWP_NoYieldSignal(&fsync_wait);
+#endif
+    return 0;
+}
+
+int BreakLaterCallBacks(void)
+{
+    struct AFSFid fid;
+    int hash;
+    afs_int32 *feip;
+    struct CallBack *cb;
+    struct FileEntry *fe = NULL;
+    struct FileEntry *myfe = NULL;
+    struct host *host;
+    struct VCBParams henumParms;
+    unsigned short tthead = 0;  /* zero is illegal value */
+    
+    /* Unchain first */
+    ViceLog(25, ("Looking for FileEntries to unchain\n"));
+    H_LOCK
+
+    /* Pick the first volume we see to clean up */
+    fid.Volume = fid.Vnode = fid.Unique = 0;
+
+    for (hash=0; hash<VHASH; hash++) {
+       for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
+           if (fe && (fe->status & FE_LATER) && 
+               (fid.Volume == 0 || fid.Volume == fe->volid)) {
+               ViceLog(125, ("Unchaining for %d:%d:%d\n", fe->vnode, 
+                             fe->unique, fe->volid));
+               fid.Volume = fe->volid;
+               *feip = fe->fnext;
+               /* Works since volid is deeper than the largest pointer */
+               ((struct object *)fe)->next = (struct object *)myfe;
+               myfe = fe;
+           } else 
+               feip = &fe->fnext;
+       }
+    }
+    
+    if (!myfe) {
+       H_UNLOCK
+       return 0;
+    }
+
+    /* loop over FEs from myfe and free/break */
+    FSYNC_UNLOCK
+    tthead = 0;
+    for (fe = myfe; fe; ) {
+       register struct CallBack *cbnext;
+       for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
+           host = h_itoh(cb->hhead);
+           h_Hold_r(host);
+           cbnext = itocb(cb->cnext);
+           if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
+               tthead = cb->thead;
+           }
+           TDel(cb);
+           HDel(cb);
+           CDel(cb, 0); /* Don't let CDel clean up the fe */
+           /* leave hold for MultiBreakVolumeCallBack to clear */
+       }
+       myfe = fe;
+       (struct object *)fe = ((struct object *)fe)->next;
+       FreeFE(myfe);
+    }
+
+    if (tthead) {
+       ViceLog(125, ("Breaking volume %d\n", fid.Volume));
+       henumParms.ncbas = 0;
+       henumParms.fid = &fid;
+       henumParms.thead = tthead;
+       H_UNLOCK
+       h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
+       H_LOCK
+           
+       if (henumParms.ncbas) {    /* do left-overs */
+           struct AFSCBFids tf;
+           tf.AFSCBFids_len = 1;
+           tf.AFSCBFids_val = &fid;
+           
+           MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
+           henumParms.ncbas = 0;
+       }
+    }  
+    FSYNC_LOCK
+    H_UNLOCK
+
+    /* Arrange to be called again */
+    return 1;
+}
+
 /*
  * Delete all timed-out call back entries (to be called periodically by file
  * server)
@@ -1298,7 +1455,7 @@ int CleanupTimedOutCallBacks_r(void)
                        itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
                        itofe(cb->fhead)->unique));
                HDel(cb);
-               CDel(cb);
+               CDel(cb, 1);
                ntimedout++;
                if (ntimedout > cbstuff.nblks) {
                  ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
@@ -1428,7 +1585,7 @@ int ClearHostCallbacks_r(struct host *hp, int locked)
          */
        cbstuff.GSS5++;
     }
-    DeleteAllCallBacks_r(hp);
+    DeleteAllCallBacks_r(hp, 1);
     if (hp->hostFlags & VENUSDOWN) {
        hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
     } else {
@@ -1681,9 +1838,9 @@ int PrintCB(register struct CallBack *cb, afs_uint32 now)
     struct FileEntry *fe = itofe(cb->fhead);
     time_t expires = TIndexToTime(cb->thead);
 
-    printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s", 
+    printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s", 
           fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
-          expires - now, ctime(&expires));
+          fe->status, expires - now, ctime(&expires));
 }
 
 #endif
@@ -1728,6 +1885,10 @@ int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *af
        i = host->interface->numberOfInterfaces;
        addr = malloc(i * sizeof(afs_int32));
        conns = malloc(i * sizeof(struct rx_connection *));
+       if (!addr || !conns) {
+           ViceLog(0, ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
+           assert(0);
+       }
 
        /* initialize alternate rx connections */
        for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
@@ -1810,8 +1971,12 @@ int MultiProbeAlternateAddress_r(struct host *host)
            sc = rxnull_NewClientSecurityObject();
 
        i = host->interface->numberOfInterfaces;
-       addr = malloc(i * sizeof(afs_int32));
+       addr = malloc(i * sizeof(afs_int32));   
        conns = malloc(i * sizeof(struct rx_connection *));
+       if (!addr || !conns) {
+           ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
+           assert(0);
+       }
 
        /* initialize alternate rx connections */
        for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)