* this package to work correctly. Every 5 minutes is suggested.
*/
+#include <afsconfig.h>
#include <afs/param.h>
+
+RCSID("$Header$");
+
#include <stdio.h>
#include <stdlib.h> /* for malloc() */
#include <time.h> /* ANSI standard location for time stuff */
#include <sys/time.h>
#include <sys/file.h>
#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
#include <afs/assert.h>
#include <afs/stds.h>
#include <afs/nfs.h> /* yuck. This is an abomination. */
#include <lwp.h>
#include <rx/rx.h>
-#include <afs/afscbint.h>
+#include <afscbint.h>
#include <afs/afsutil.h>
#include <lock.h>
#include <afs/ihandle.h>
#include <afs/vnode.h>
#include <afs/volume.h>
+#include "viced_prototypes.h"
#include "viced.h"
#include <afs/ptclient.h> /* need definition of prlist for host.h */
#include "host.h"
-
+extern afsUUID FS_HostUUID;
extern int hostCount;
int ShowProblems = 1;
/* max time to break a callback, otherwise client is dead or net is hosed */
#define MAXCBT 25
-#define u_short unsigned short
#define u_byte unsigned char
struct cbcounters cbstuff;
struct cbstruct {
struct host * hp;
- u_short thead;
+ afs_uint32 thead;
} ;
struct FileEntry {
- afs_uint32 vnode; /* XXX This was u_short XXX */
- afs_uint32 unique;
+ afs_uint32 vnode;
+ afs_uint32 unique;
afs_uint32 volid;
- u_short fnext;
- u_short ncbs;
- u_short firstcb;
- u_short spare;
-#ifdef AFS_ALPHA_ENV
- u_short spare1;
- u_short spare2;
-#endif
+ 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 {
- u_short cnext; /* Next call back entry */
- u_short fhead; /* Head of this call back chain */
+ afs_uint32 cnext; /* Next call back entry */
+ afs_uint32 fhead; /* Head of this call back chain */
u_byte thead; /* Head of timeout chain */
u_byte status; /* Call back status; see definitions, below */
- u_short hhead; /* Head of host table chain */
- u_short tprev, tnext; /* Timeout chain */
- u_short hprev, hnext; /* Chain from host table */
+ afs_uint32 hhead; /* Head of host table chain */
+ afs_uint32 tprev, tnext; /* Timeout chain */
+ afs_uint32 hprev, hnext; /* Chain from host table */
+ unsigned short spare; /* make it a multiple of 32 bits. */
} *CB; /* Don't use CB[0] */
-/* status bits for status field of CallBack structure */
+/* status values for status field of CallBack structure */
#define CB_NORMAL 1 /* Normal call back */
#define CB_DELAYED 2 /* Delayed call back due to rpc problems.
The call back entry will be added back to the
#define ServerBias (3*60)
/* Heads of CB queues; a timeout index is 1+index into this array */
-static u_short timeout[128];
+static afs_uint32 timeout[128];
/* Convert cbtime to timeout queue index */
#define TIndex(cbtime) (((cbtime)&127)+1)
struct object *next;
};
+struct VCBParams {
+ struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
+ unsigned int ncbas;
+ afs_uint32 thead; /* head of timeout queue for youngest callback */
+ struct AFSFid *fid;
+};
+
struct CallBack *CBfree = 0;
struct FileEntry *FEfree = 0;
+/* Prototypes for static routines */
+static struct FileEntry *FindFE (register AFSFid *fid);
static struct CallBack *iGetCB(register int *nused);
-#define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
+static int iFreeCB(register struct CallBack *cb, register int *nused);
static struct FileEntry *iGetFE(register int *nused);
+static int iFreeFE(register struct FileEntry *fe, register int *nused);
+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, 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, 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);
+static int ClearHostCallbacks_r(struct host *hp, int locked);
+
+#define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
#define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
#define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
#define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
+/* Other protos - move out sometime */
+extern void ShutDown();
+
#define VHASH 512 /* Power of 2 */
-static u_short HashTable[VHASH]; /* File entry hash table */
+static afs_uint32 HashTable[VHASH]; /* File entry hash table */
#define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
-static struct FileEntry *FindFE (fid)
- register AFSFid *fid;
-
+static struct FileEntry *FindFE (register AFSFid *fid)
{
int hash;
- register fei;
+ register int fei;
register struct FileEntry *fe;
hash = VHash(fid->Volume, fid->Unique);
return fe;
}
return 0;
-
-} /*FindFE*/
-
+}
#ifndef INTERPRET_DUMP
-extern void ShutDown();
-static CDelPtr(), FDel(), AddCallback1(), GetSomeSpace_r();
-
static struct CallBack *iGetCB(register int *nused)
{
register struct CallBack *ret;
- if (ret = CBfree) {
+ if ((ret = CBfree)) {
CBfree = (struct CallBack *)(((struct object *)ret)->next);
(*nused)++;
}
return ret;
+}
-} /*cb_GetCB*/
-
-
-static iFreeCB(cb, nused)
- register struct CallBack *cb;
- register int *nused;
-
+static int iFreeCB(register struct CallBack *cb, register int *nused)
{
((struct object *)cb)->next = (struct object *)CBfree;
CBfree = cb;
(*nused)--;
-} /*FreeCB*/
-
+ return 0;
+}
static struct FileEntry *iGetFE(register int *nused)
{
register struct FileEntry *ret;
- if (ret = FEfree) {
+ if ((ret = FEfree)) {
FEfree = (struct FileEntry *)(((struct object *)ret)->next);
(*nused)++;
}
return ret;
+}
-} /*cb_GetFE*/
-
-
-static iFreeFE(fe, nused)
- register struct FileEntry *fe;
- register int *nused;
-
+static int iFreeFE(register struct FileEntry *fe, register int *nused)
{
((struct object *)fe)->next = (struct object *)FEfree;
FEfree = fe;
(*nused)--;
-} /*FreeFE*/
-
+ return 0;
+}
/* Add cb to end of specified timeout list */
-static TAdd(cb, thead)
- register struct CallBack *cb;
- register u_short *thead;
-
+static int TAdd(register struct CallBack *cb, register afs_uint32 *thead)
{
if (!*thead) {
(*thead) = cb->tnext = cb->tprev = cbtoi(cb);
cb->tprev = thp->tprev;
cb->tnext = *thead;
- thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
+ if (thp) {
+ if (thp->tprev)
+ thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
+ else
+ thp->tprev = cbtoi(cb);
+ }
}
cb->thead = ttoi(thead);
-
-} /*TAdd*/
-
+ return 0;
+}
/* Delete call back entry from timeout list */
-static TDel(cb)
- register struct CallBack *cb;
-
+static int TDel(register struct CallBack *cb)
{
- register u_short *thead = itot(cb->thead);
+ register afs_uint32 *thead = itot(cb->thead);
if (*thead == cbtoi(cb))
*thead = (*thead == cb->tnext? 0: cb->tnext);
- itocb(cb->tprev)->tnext = cb->tnext;
- itocb(cb->tnext)->tprev = cb->tprev;
-
-} /*TDel*/
-
+ if (itocb(cb->tprev))
+ itocb(cb->tprev)->tnext = cb->tnext;
+ if (itocb(cb->tnext))
+ itocb(cb->tnext)->tprev = cb->tprev;
+ return 0;
+}
/* Add cb to end of specified host list */
-static HAdd(cb, host)
- register struct CallBack *cb;
- register struct host *host;
-
+static int HAdd(register struct CallBack *cb, register struct host *host)
{
cb->hhead = h_htoi(host);
if (!host->cblist) {
cb->hnext = host->cblist;
hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
}
-
-} /*HAdd*/
-
+ return 0;
+}
/* Delete call back entry from host list */
-static HDel(cb)
- register struct CallBack *cb;
-
+static int HDel(register struct CallBack *cb)
{
- register u_short *hhead = &h_itoh(cb->hhead)->cblist;
+ register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
if (*hhead == cbtoi(cb))
*hhead = (*hhead == cb->hnext? 0: cb->hnext);
itocb(cb->hprev)->hnext = cb->hnext;
itocb(cb->hnext)->hprev = cb->hprev;
-
-} /*HDel*/
-
+ return 0;
+}
/* Delete call back entry from fid's chain of cb's */
/* 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 CDel(cb)
- struct CallBack *cb;
-
+static int CDel(struct CallBack *cb, int deletefe)
{
int cbi = cbtoi(cb);
struct FileEntry *fe = itofe(cb->fhead);
- register u_short *cbp;
+ register afs_uint32 *cbp;
register int safety;
for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
assert(0);
ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
DumpCallBackState();
- ShutDown();
+ ShutDownAndCore(PANIC);
}
}
- CDelPtr(fe, cbp);
-
-} /*CDel*/
-
+ CDelPtr(fe, cbp, deletefe);
+ return 0;
+}
/* Same as CDel, but pointer to parent pointer to CB entry is passed,
* as well as file entry */
* routine */
int Ccdelpt=0, CcdelB=0;
-static CDelPtr(fe, cbp)
- register struct FileEntry *fe;
- register u_short *cbp;
-
+static int CDelPtr(register struct FileEntry *fe,
+ register afs_uint32 *cbp, int deletefe)
{
register struct CallBack *cb;
if (!*cbp)
- return;
+ return 0;
Ccdelpt++;
cb = itocb(*cbp);
if (cb != &CB[*cbp])
CcdelB++;
*cbp = cb->cnext;
FreeCB(cb);
- if (--fe->ncbs == 0)
+ if (deletefe && (--fe->ncbs == 0))
FDel(fe);
+ return 0;
+}
-} /*CDelPtr*/
-
-
-static u_short *FindCBPtr(fe, host)
- struct FileEntry *fe;
- struct host *host;
-
+static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host)
{
register afs_uint32 hostindex = h_htoi(host);
register struct CallBack *cb;
- register u_short *cbp;
+ register afs_uint32 *cbp;
register int safety;
for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
if (safety > cbstuff.nblks) {
ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
DumpCallBackState();
- ShutDown();
+ ShutDownAndCore(PANIC);
}
cb = itocb(*cbp);
if (cb->hhead == hostindex)
break;
}
return cbp;
-
-} /*FindCBPtr*/
-
-
+}
/* Delete file entry from hash table */
-static FDel(fe)
- register struct FileEntry *fe;
-
+static int FDel(register struct FileEntry *fe)
{
register int fei = fetoi(fe);
- register unsigned short *p = &HashTable[VHash(fe->volid, fe->unique)];
+ register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
while (*p && *p != fei)
p = &itofe(*p)->fnext;
assert(*p);
*p = fe->fnext;
FreeFE(fe);
+ return 0;
+}
-} /*FDel*/
-
-
-
-InitCallBack(nblks)
- int nblks;
+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 */
cbstuff.nblks = nblks;
cbstuff.nbreakers = 0;
H_UNLOCK
+ return 0;
+}
-} /*InitCallBack*/
-
-
-afs_int32 XCallBackBulk_r(ahost, fids, nfids)
- struct host *ahost;
- struct AFSFid *fids;
- afs_int32 nfids;
-
+afs_int32 XCallBackBulk_r(struct host *ahost, struct AFSFid *fids,
+ afs_int32 nfids)
{
struct AFSCallBack tcbs[AFSCBMAX];
register int i;
}
return code;
-} /*XCallBackBulk*/
-
+}
/* the locked flag tells us if the host entry has already been locked
* by our parent. I don't think anybody actually calls us with the
* as well. If so, the host->ResetDone should probably be set to 0,
* and we probably don't want to return a callback promise to the
* cache manager, either. */
-int
-AddCallBack1(host, fid, thead, type, locked)
- struct host *host;
- AFSFid *fid;
- int locked;
- int type;
- u_short *thead;
+int AddCallBack1(struct host *host, AFSFid *fid, afs_uint32 *thead,
+ int type, int locked)
{
int retVal;
H_LOCK
return retVal;
}
-int
-AddCallBack1_r(host, fid, thead, type, locked)
- struct host *host;
- AFSFid *fid;
- int locked;
- int type;
- u_short *thead;
+static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead,
+ int type, int locked)
{
struct FileEntry *fe;
struct CallBack *cb = 0, *lastcb = 0;
struct FileEntry *newfe = 0;
afs_uint32 time_out;
- u_short *Thead = thead;
+ afs_uint32 *Thead = thead;
struct CallBack *newcb = 0;
int safety;
register afs_uint32 hash;
fe = newfe;
- newfe = (struct FileEntry *) 0;
+ newfe = NULL;
fe->firstcb = 0;
fe->volid = fid->Volume;
fe->vnode = fid->Vnode;
if (safety > cbstuff.nblks) {
ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
DumpCallBackState();
- ShutDown();
+ ShutDownAndCore(PANIC);
}
if (cb->hhead == h_htoi(host))
break;
}
} else {
cb = newcb;
- newcb = (struct CallBack *) 0;
+ newcb = NULL;
*(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
fe->ncbs++;
cb->cnext = 0;
if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
return time_out-ServerBias; /* Expires sooner at workstation */
-return 0;
-} /*AddCallBack1*/
-
+ return 0;
+}
/* Take an array full of hosts, all held. Break callbacks to them, and
* release the holds once you're done, except don't release xhost. xhost
* which is sufficient only if VenusDown = 0 only happens when the
* lock is held over the RPC and the subsequent VenusDown == 0
* wherever that is done. */
-static void MultiBreakCallBack_r(cba, ncbas, afidp, xhost)
- struct cbstruct cba[];
- int ncbas;
- struct AFSCBFids *afidp;
- struct host * xhost;
+static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
+ struct AFSCBFids *afidp, struct host *xhost)
{
int i,j;
struct rx_connection *conns[MAX_CB_HOSTS];
multi_Rx(conns, j) {
multi_RXAFSCB_CallBack(afidp, &tc);
if (multi_error) {
- unsigned short idx ;
+ afs_uint32 idx ;
struct host *hp;
+ char hoststr[16];
+
idx = 0;
/* If there's an error, we have to hunt for the right host.
* The conns array _should_ correspond one-to-one to the cba
{
if (ShowProblems) {
ViceLog(7,
- ("BCB: Failed on file %u.%d.%d, host %x.%d is down\n",
+ ("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, hp->host, hp->port));
+ afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), ntohs(hp->port)));
}
H_LOCK
h_Release_r(hp);
}
-return ;
+ return;
}
/*
* again after it was locked. That race condition is incredibly rare and
* relatively harmless even when it does occur, so we don't check for it now.
*/
-BreakCallBack(xhost, fid, flag)
- struct host *xhost;
- int flag; /* if flag is true, send a break callback msg to "host", too */
- AFSFid *fid;
+/* if flag is true, send a break callback msg to "host", too */
+int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
{
struct FileEntry *fe;
struct CallBack *cb, *nextcb;
struct rx_connection *conns[MAX_CB_HOSTS];
struct AFSCBFids tf;
int hostindex;
+ char hoststr[16];
- ViceLog(7,("BCB: BreakCallBack(all but %x.%d, (%u,%d,%d))\n",
- xhost->host, xhost->port, fid->Volume, fid->Vnode,
+ ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
+ afs_inet_ntoa_r(xhost->host,hoststr), ntohs(xhost->port), fid->Volume, fid->Vnode,
fid->Unique));
H_LOCK
ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
}
else if (thishost->hostFlags & VENUSDOWN) {
- ViceLog(7,("BCB: %x.%d is down; delaying break call back\n",
- thishost->host, thishost->port));
+ ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
+ 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 */
}
}
}
done:
H_UNLOCK
- return;
-} /*BreakCallBack*/
-
+ return 0;
+}
/* Delete (do not break) single call back for fid */
-DeleteCallBack(host, fid)
- struct host *host;
- AFSFid *fid;
-
+int DeleteCallBack(struct host *host, AFSFid *fid)
{
register struct FileEntry *fe;
- register u_short *pcb;
+ register afs_uint32 *pcb;
+ char hoststr[16];
+
cbstuff.DeleteCallBacks++;
H_LOCK
H_UNLOCK
ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
fid->Volume, fid->Vnode, fid->Unique));
- return;
+ return 0;
}
pcb = FindCBPtr(fe, host);
if (!*pcb) {
- ViceLog(8,("DCB: No call back for host %x.%d, (%u, %d, %d)\n",
- host->host, host->port, fid->Volume, fid->Vnode, fid->Unique));
+ ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
+ afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), fid->Volume, fid->Vnode, fid->Unique));
h_Unlock_r(host);
H_UNLOCK
- return;
+ return 0;
}
HDel(itocb(*pcb));
TDel(itocb(*pcb));
- CDelPtr(fe, pcb);
+ CDelPtr(fe, pcb, 1);
h_Unlock_r(host);
H_UNLOCK
-
-} /*DeleteCallBack*/
-
+ return 0;
+}
/*
* Delete (do not break) all call backs for fid. This call doesn't
* since we're not adding callbacks, but deleting them. I'm not sure
* why it doesn't set the lock, however; perhaps it should.
*/
-DeleteFileCallBacks(fid)
- AFSFid *fid;
+int DeleteFileCallBacks(AFSFid *fid)
{
register struct FileEntry *fe;
register struct CallBack *cb;
register afs_uint32 cbi;
- register n;
+ register int n;
H_LOCK
cbstuff.DeleteFiles++;
H_UNLOCK
ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
fid->Volume, fid->Vnode, fid->Unique));
- return;
+ return 0;
}
for (n=0,cbi = fe->firstcb; cbi; n++) {
cb = itocb(cbi);
}
FDel(fe);
H_UNLOCK
-
-} /*DeleteFileCallBacks*/
-
+ return 0;
+}
/* Delete (do not break) all call backs for host. The host should be
* locked. */
-DeleteAllCallBacks(host)
- struct host *host;
-{
- int retVal;
- H_LOCK
- retVal = DeleteAllCallBacks_r(host);
- H_UNLOCK
- return retVal;
-}
-
-DeleteAllCallBacks_r(host)
- struct host *host;
+int DeleteAllCallBacks_r(struct host *host, int deletefe)
{
register struct CallBack *cb;
register int cbi, first;
cbi = first = host->cblist;
if (!cbi) {
ViceLog(8,("DV: no call backs\n"));
- return;
+ return 0;
}
do {
cb = itocb(cbi);
cbi = cb->hnext;
TDel(cb);
- CDel(cb);
+ CDel(cb, deletefe);
} while (cbi != first);
host->cblist = 0;
-
-} /*DeleteAllCallBacks*/
-
+ return 0;
+}
/*
* Break all delayed call backs for host. Returns 1 if all call backs
* successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
* Must be called with VenusDown set for this host
*/
-int BreakDelayedCallBacks(host)
- struct host *host;
+int BreakDelayedCallBacks(struct host *host)
{
int retVal;
H_LOCK
return retVal;
}
-extern afsUUID FS_HostUUID;
-
-int BreakDelayedCallBacks_r(host)
- struct host *host;
+int BreakDelayedCallBacks_r(struct host *host)
{
struct AFSFid fids[AFSCBMAX];
- u_short thead[AFSCBMAX];
+ u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
int cbi, first, nfids;
struct CallBack *cb;
struct interfaceAddr interf;
int code;
+ char hoststr[16];
cbstuff.nbreakers++;
if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
if (code) {
if (ShowProblems) {
ViceLog(0,
- ("CB: Call back connect back failed (in break delayed) for %x.%d\n",
- host->host, host->port));
+ ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
+ afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
}
host->hostFlags |= VENUSDOWN;
}
else {
- ViceLog(25,("InitCallBackState success on %x\n",host->host));
+ ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
/* reset was done successfully */
host->hostFlags |= RESETDONE;
host->hostFlags &= ~VENUSDOWN;
nfids++;
HDel(cb);
TDel(cb);
- CDel(cb);
+ CDel(cb, 1);
}
} while (cbi && cbi != first && nfids < AFSCBMAX);
int i;
if (ShowProblems) {
ViceLog(0,
- ("CB: XCallBackBulk failed, host=%x.%d; callback list follows:\n",
- host->host, host->port));
+ ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
+ afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
}
for (i = 0; i<nfids; i++) {
if (ShowProblems) {
ViceLog(0,
- ("CB: Host %x.%d, file %u.%u.%u (part of bulk callback)\n",
- host->host, host->port,
+ ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
+ 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);
-
-} /*BreakDelayedCallBacks*/
-
-
-struct VCBParams {
- struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
- unsigned int ncbas;
- unsigned short thead; /* head of timeout queue for youngest callback */
- struct AFSFid *fid;
-};
+}
/*
** isheld is 0 if the host is held in h_Enumerate
** isheld is 1 if the host is held in BreakVolumeCallBacks
*/
-static int MultiBreakVolumeCallBack_r (host, isheld, parms)
- struct host *host;
- int isheld;
- struct VCBParams *parms;
+static int MultiBreakVolumeCallBack_r(struct host *host,
+ int isheld, struct VCBParams *parms, int deletefe)
{
+ char hoststr[16];
+
if ( !isheld )
return isheld; /* host is held only by h_Enumerate, do nothing */
if ( host->hostFlags & HOSTDELETED )
h_Unlock_r(host);
return 0; /* Release hold */
}
- ViceLog(8,("BVCB: volume call back for host %x.%d failed\n",
- host->host,host->port));
+ ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
+ afs_inet_ntoa_r(host->host,hoststr),ntohs(host->port)));
if (ShowProblems) {
- ViceLog(0, ("CB: volume callback for host %x.%d failed\n",
- host->host, host->port));
+ ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
+ 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 */
** isheld is 0 if the host is held in h_Enumerate
** isheld is 1 if the host is held in BreakVolumeCallBacks
*/
-static int MultiBreakVolumeCallBack (host, isheld, parms)
- struct host *host;
- int isheld;
- struct VCBParams *parms;
+static int MultiBreakVolumeCallBack(struct host *host, int isheld,
+ struct VCBParams *parms)
+{
+ int retval;
+ H_LOCK
+ 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);
+ retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
H_UNLOCK
return retval;
}
* a delayed callback. Resets will be forced if the host is
* determined to be down before the RPC is executed.
*/
-BreakVolumeCallBacks(volume)
- afs_uint32 volume;
-
+int BreakVolumeCallBacks(afs_uint32 volume)
{
struct AFSFid fid;
int hash;
- u_short *feip;
+ afs_uint32 *feip;
struct CallBack *cb;
struct FileEntry *fe;
struct host *host;
struct VCBParams henumParms;
- unsigned short tthead = 0; /* zero is illegal value */
+ afs_uint32 tthead = 0; /* zero is illegal value */
H_LOCK
fid.Volume = volume, fid.Vnode = fid.Unique = 0;
for (hash=0; hash<VHASH; hash++) {
- for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
+ for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
if (fe->volid == volume) {
register struct CallBack *cbnext;
for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
}
H_UNLOCK
-return 0;
-} /*BreakVolumeCallBacks*/
+ 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;
+ fe = (struct FileEntry *)((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)
*/
-CleanupTimedOutCallBacks()
+int CleanupTimedOutCallBacks(void)
{
H_LOCK
CleanupTimedOutCallBacks_r();
H_UNLOCK
}
-CleanupTimedOutCallBacks_r()
+int CleanupTimedOutCallBacks_r(void)
{
afs_uint32 now = CBtime(FT_ApproxTime());
- register u_short *thead;
+ register afs_uint32 *thead;
register struct CallBack *cb;
register int ntimedout = 0;
- extern void ShutDown();
+ char hoststr[16];
while (tfirst <= now) {
register int cbi;
do {
cb = itocb(cbi);
cbi = cb->tnext;
- ViceLog(8,("CCB: deleting timed out call back %x.%d, (%u,%u,%u)\n",
- h_itoh(cb->hhead)->host, h_itoh(cb->hhead)->port,
+ ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
+ afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
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"));
DumpCallBackState();
- ShutDown();
+ ShutDownAndCore(PANIC);
}
} while (cbi != *thead);
*thead = 0;
cbstuff.CBsTimedOut += ntimedout;
ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
return (ntimedout > 0);
-
-} /*CleanupTimedOutCallBacks*/
-
+}
static struct host *lih_host;
-static int lih_r(host, held, hostp)
- register struct host *host, *hostp;
- register int held;
-
+static int lih_r(register struct host *host, register int held,
+ register struct host *hostp)
{
if (host->cblist
&& ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
lih_host = host;
}
return held;
-
-} /*lih*/
-
+}
/* This could be upgraded to get more space each time */
/* first pass: find the oldest host which isn't held by anyone */
/* second pass: find the oldest host who isn't "me" */
/* always called with hostp unlocked */
-static int GetSomeSpace_r(hostp, locked)
- struct host *hostp;
- int locked;
+extern struct host *hostList;
+static int GetSomeSpace_r(struct host *hostp, int locked)
{
- register struct host *hp, *hp1 = (struct host *)0;
+ register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
int i=0;
cbstuff.GotSomeSpaces++;
ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
if (CleanupTimedOutCallBacks_r()) {
cbstuff.GSS3++;
- return;
+ return 0;
}
do {
lih_host = 0;
- h_Enumerate_r(lih_r, (char *)hp1);
+ h_Enumerate_r(lih_r, hp2, (char *)hp1);
hp = lih_host;
if (hp) {
cbstuff.GSS4++;
if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
- return;
+ return 0;
+ hp2 = hp->next;
} else {
+ hp2 = hostList;
hp1 = hostp;
cbstuff.GSS1++;
ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
if (!locked) {
h_Unlock_r(hostp);
}
-} /*GetSomeSpace*/
-
-
-ClearHostCallbacks(hp, locked)
- struct host *hp;
- int locked; /* set if caller has already locked the host */
-{
- int retVal;
- H_LOCK
- retVal = ClearHostCallbacks_r(hp, locked);
- H_UNLOCK
- return retVal;
+ return 0;
}
-int ClearHostCallbacks_r(hp, locked)
- struct host *hp;
- int locked; /* set if caller has already locked the host */
+/* locked - set if caller has already locked the host */
+static int ClearHostCallbacks_r(struct host *hp, int locked)
{
struct interfaceAddr interf;
int code;
int held = 0;
+ char hoststr[16];
- ViceLog(5,("GSS: Delete longest inactive host %x\n", hp->host));
+ ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
if ( !(held = h_Held_r(hp)) )
h_Hold_r(hp);
*/
cbstuff.GSS5++;
}
- DeleteAllCallBacks_r(hp);
+ DeleteAllCallBacks_r(hp, 1);
if (hp->hostFlags & VENUSDOWN) {
hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
} else {
#endif /* INTERPRET_DUMP */
-PrintCallBackStats()
-
+int PrintCallBackStats(void)
{
fprintf(stderr, "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
-} /*PrintCallBackStats*/
-
+ return 0;
+}
#define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
#ifndef INTERPRET_DUMP
-
-DumpCallBackState()
-
+int DumpCallBackState(void)
{
int fd;
afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0) {
ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
- return;
+ return 0;
}
write(fd, &magic, sizeof(magic));
write(fd, &now, sizeof(now));
write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
close(fd);
-} /*DumpCallBackState*/
+ return 0;
+}
#endif
/* This is only compiled in for the callback analyzer program */
/* Returns the time of the dump */
-time_t ReadDump(file)
- char *file;
-
+time_t ReadDump(char *file)
{
int fd;
afs_uint32 magic, freelisthead;
exit(1);
}
return now;
-
-} /*ReadDump*/
-
+}
#include "AFS_component_version_number.c"
-main(argc, argv)
- int argc;
- char **argv;
-
+int main(int argc, char **argv)
{
int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
static AFSFid fid;
register struct CallBack *cb;
time_t now;
- bzero(&fid, sizeof(fid));
+ memset(&fid, 0, sizeof(fid));
argc--; argv++;
while (argc && **argv == '-') {
noptions++;
}
if (err || argc != 1) {
fprintf(stderr,
- "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
+ "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
exit(1);
}
}
if (all || vol) {
register hash;
- register u_short *feip;
+ register afs_uint32 *feip;
register struct CallBack *cb;
register struct FileEntry *fe;
}
}
if (cbi) {
- u_short cfirst = cbi;
+ afs_uint32 cfirst = cbi;
do {
cb = itocb(cbi);
PrintCB(cb,now);
}
}
-PrintCB(cb, now)
- register struct CallBack *cb;
- afs_uint32 now;
-
+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));
-
-} /*PrintCB*/
-
+ fe->status, expires - now, ctime(&expires));
+}
#endif
** try breaking calbacks on afidp from host. Use multi_rx.
** return 0 on success, non-zero on failure
*/
-int
-MultiBreakCallBackAlternateAddress(host, afidp)
-struct host* host;
-struct AFSCBFids* afidp;
+int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
{
int retVal;
H_LOCK
return retVal;
}
-int
-MultiBreakCallBackAlternateAddress_r(host, afidp)
-struct host* host;
-struct AFSCBFids* afidp;
+int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
{
int i,j;
- struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
+ struct rx_connection** conns;
struct rx_connection* connSuccess = 0;
- afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
+ afs_int32 *addr;
static struct rx_securityClass *sc = 0;
static struct AFSCBs tc = {0,0};
+ char hoststr[16];
/* nothing more can be done */
if ( !host->interface ) return 1; /* failure */
/* initialise a security object only once */
if ( !sc )
- sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
+ sc = rxnull_NewClientSecurityObject();
+
+ 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++)
}
assert(j); /* at least one alternate address */
- ViceLog(125,("Starting multibreakcall back on all addr for host:%x\n",
- host->host));
+ ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
+ afs_inet_ntoa_r(host->host,hoststr)));
H_UNLOCK
multi_Rx(conns, j)
{
connSuccess = conns[multi_i];
rx_SetConnDeadTime(host->callback_rxcon, 50);
rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
- ViceLog(125,("multibreakcall success with addr:%x\n",
- addr[multi_i]));
+ ViceLog(125,("multibreakcall success with addr %s\n",
+ afs_inet_ntoa_r(addr[multi_i],hoststr)));
H_UNLOCK
multi_Abort;
}
if ( conns[i] != connSuccess )
rx_DestroyConnection(conns[i] );
+ free(addr);
+ free(conns);
+
if ( connSuccess ) return 0; /* success */
else return 1; /* failure */
}
** try multiRX probes to host.
** return 0 on success, non-zero on failure
*/
-int
-MultiProbeAlternateAddress_r(host)
-struct host* host;
+int MultiProbeAlternateAddress_r(struct host *host)
{
int i,j;
- struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
+ struct rx_connection** conns;
struct rx_connection* connSuccess = 0;
- afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
+ afs_int32 *addr;
static struct rx_securityClass *sc = 0;
+ char hoststr[16];
/* nothing more can be done */
if ( !host->interface ) return 1; /* failure */
/* initialise a security object only once */
if ( !sc )
- sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
+ sc = rxnull_NewClientSecurityObject();
+
+ 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 MultiProbeAlternateAddress_r\n"));
+ assert(0);
+ }
/* initialize alternate rx connections */
for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
}
assert(j); /* at least one alternate address */
- ViceLog(125,("Starting multiprobe on all addr for host:%x\n",
- host->host));
+ ViceLog(125,("Starting multiprobe on all addr for host %s\n",
+ afs_inet_ntoa_r(host->host,hoststr)));
H_UNLOCK
multi_Rx(conns, j)
{
connSuccess = conns[multi_i];
rx_SetConnDeadTime(host->callback_rxcon, 50);
rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
- ViceLog(125,("multiprobe success with addr:%x\n",
- addr[multi_i]));
+ ViceLog(125,("multiprobe success with addr %s\n",
+ afs_inet_ntoa_r(addr[multi_i],hoststr)));
H_UNLOCK
multi_Abort;
}
if ( conns[i] != connSuccess )
rx_DestroyConnection(conns[i] );
+ free(addr);
+ free(conns);
+
if ( connSuccess ) return 0; /* success */
else return 1; /* failure */
}