#include <afs/ptclient.h> /* need definition of prlist for host.h */
#include "host.h"
-
+extern afsUUID FS_HostUUID;
extern int hostCount;
int ShowProblems = 1;
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 */
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);
/* 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);
ShutDown();
}
}
- CDelPtr(fe, cbp);
+ CDelPtr(fe, cbp, deletefe);
return 0;
}
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;
CcdelB++;
*cbp = cb->cnext;
FreeCB(cb);
- if (--fe->ncbs == 0)
+ if (deletefe && (--fe->ncbs == 0))
FDel(fe);
return 0;
}
{
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 */
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
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
}
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 {
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 */
}
}
}
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;
/* 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;
cb = itocb(cbi);
cbi = cb->hnext;
TDel(cb);
- CDel(cb);
+ CDel(cb, deletefe);
} while (cbi != first);
host->cblist = 0;
return 0;
return retVal;
}
-extern afsUUID FS_HostUUID;
-
int BreakDelayedCallBacks_r(struct host *host)
{
struct AFSFid fids[AFSCBMAX];
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;
}
nfids++;
HDel(cb);
TDel(cb);
- CDel(cb);
+ CDel(cb, 1);
}
} while (cbi && cbi != first && nfids < AFSCBMAX);
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:
}
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);
}
** 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];
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 */
{
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;
}
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)
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"));
*/
cbstuff.GSS5++;
}
- DeleteAllCallBacks_r(hp);
+ DeleteAllCallBacks_r(hp, 1);
if (hp->hostFlags & VENUSDOWN) {
hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
} else {
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
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++)
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++)