#include <afsconfig.h>
#include <afs/param.h>
+#include <afs/stds.h>
+#include <roken.h>
-#include <stdio.h>
-#include <stdlib.h> /* for malloc() */
-#include <time.h> /* ANSI standard location for time stuff */
-#include <string.h>
-#ifdef AFS_NT40_ENV
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <sys/time.h>
+#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
-#include <unistd.h>
#endif
-#include <afs/assert.h>
-
-#include <afs/stds.h>
#include <afs/nfs.h> /* yuck. This is an abomination. */
#include <lwp.h>
#include "host.h"
#include "callback.h"
#ifdef AFS_DEMAND_ATTACH_FS
-#include "../tviced/serialize_state.h"
+#include "serialize_state.h"
#endif /* AFS_DEMAND_ATTACH_FS */
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 AFSCBFids *afidp);
+static int MultiBreakVolumeCallBack_r(struct host *host,
struct VCBParams *parms, int deletefe);
-static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
- void *rock);
+static int MultiBreakVolumeLaterCallBack(struct host *host, void *rock);
static int GetSomeSpace_r(struct host *hostp, int locked);
static int ClearHostCallbacks_r(struct host *hp, int locked);
static int DumpCallBackState_r(void);
for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
cbp = &itocb(*cbp)->cnext, safety++) {
if (safety > cbstuff.nblks + 10) {
- assert(0);
- ViceLog(0,
- ("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",
- cbi, fe->firstcb, *cbp));
+ ViceLogThenPanic(0, ("CDel: Internal Error -- shutting down: "
+ "wanted %d from %d, now at %d\n",
+ cbi, fe->firstcb, *cbp));
DumpCallBackState_r();
ShutDownAndCore(PANIC);
}
while (*p && *p != fei)
p = &itofe(*p)->fnext;
- assert(*p);
+ osi_Assert(*p);
*p = fe->fnext;
FreeFE(fe);
return 0;
* FE[0] and CB[0] are not used--and not allocated */
FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry))));
if (!FE) {
- ViceLog(0, ("Failed malloc in InitCallBack\n"));
- assert(0);
+ ViceLogThenPanic(0, ("Failed malloc in InitCallBack\n"));
}
FE--; /* FE[0] is supposed to point to junk */
cbstuff.nFEs = nblks;
FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack))));
if (!CB) {
- ViceLog(0, ("Failed malloc in InitCallBack\n"));
- assert(0);
+ ViceLogThenPanic(0, ("Failed malloc in InitCallBack\n"));
}
CB--; /* CB[0] is supposed to point to junk */
cbstuff.nCBs = nblks;
int j;
struct rx_connection *cb_conn = NULL;
-#ifdef ADAPT_MTU
rx_SetConnDeadTime(ahost->callback_rxcon, 4);
rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
-#endif
code = 0;
j = 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
- * may be NULL. Currently only works for a single Fid in afidp array.
+ * release the holds once you're done.
+ * Currently only works for a single Fid in afidp array.
* If you want to make this work with multiple fids, you need to fix
* the error handling. One approach would be to force a reset if a
* multi-fid call fails, or you could add delayed callbacks for each
* wherever that is done. */
static void
MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
- struct AFSCBFids *afidp, struct host *xhost)
+ struct AFSCBFids *afidp)
{
int i, j;
struct rx_connection *conns[MAX_CB_HOSTS];
static struct AFSCBs tc = { 0, 0 };
int multi_to_cba_map[MAX_CB_HOSTS];
- assert(ncbas <= MAX_CB_HOSTS);
+ osi_Assert(ncbas <= MAX_CB_HOSTS);
/* sort cba list to avoid makecall issues */
qsort(cba, ncbas, sizeof(struct cbstruct), CompareCBA);
multi_to_cba_map[j] = i;
conns[j++] = thishost->callback_rxcon;
-#ifdef ADAPT_MTU
rx_SetConnDeadTime(thishost->callback_rxcon, 4);
rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
-#endif
}
if (j) { /* who knows what multi would do with 0 conns? */
for (i = 0; i < ncbas; i++) {
struct host *hp;
hp = cba[i].hp;
- if (hp && xhost != hp) {
+ if (hp) {
h_Release_r(hp);
}
}
{
struct FileEntry *fe;
struct CallBack *cb, *nextcb;
- struct cbstruct cba[MAX_CB_HOSTS];
- int ncbas;
+ struct cbstruct cbaDef[MAX_CB_HOSTS], *cba = cbaDef;
+ unsigned int ncbas, cbaAlloc = MAX_CB_HOSTS;
struct AFSCBFids tf;
int hostindex;
char hoststr[16];
- ViceLog(7,
- ("BCB: BreakCallBack(Host %p all but %s:%d, (%u,%u,%u))\n",
- xhost, afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
- fid->Volume, fid->Vnode, fid->Unique));
+ if (xhost)
+ ViceLog(7,
+ ("BCB: BreakCallBack(Host %p all but %s:%d, (%u,%u,%u))\n",
+ xhost, afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
+ fid->Volume, fid->Vnode, fid->Unique));
+ else
+ ViceLog(7,
+ ("BCB: BreakCallBack(No Host, (%u,%u,%u))\n",
+ fid->Volume, fid->Vnode, fid->Unique));
H_LOCK;
cbstuff.BreakCallBacks++;
if (!fe) {
goto done;
}
- hostindex = h_htoi(xhost);
+ hostindex = xhost ? h_htoi(xhost) : 0;
cb = itocb(fe->firstcb);
if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
/* the most common case is what follows the || */
tf.AFSCBFids_len = 1;
tf.AFSCBFids_val = fid;
- for (; cb;) {
- for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
+ for (ncbas = 0; cb ; cb = nextcb) {
nextcb = itocb(cb->cnext);
if ((cb->hhead != hostindex || flag)
&& (cb->status == CB_BULK || cb->status == CB_NORMAL
} else {
if (!(thishost->hostFlags & HOSTDELETED)) {
h_Hold_r(thishost);
+ if (ncbas == cbaAlloc) { /* Need more space */
+ int curLen = cbaAlloc*sizeof(cba[0]);
+ struct cbstruct *cbaOld = (cba == cbaDef) ? NULL : cba;
+
+ /* There are logical contraints elsewhere that the number of hosts
+ (i.e. h_HTSPERBLOCK*h_MAXHOSTTABLES) remains in the realm of a signed "int".
+ cbaAlloc is defined unsigned int hence doubling below cannot overflow
+ */
+ cbaAlloc = cbaAlloc<<1; /* double */
+ cba = realloc(cbaOld, cbaAlloc * sizeof(cba[0]));
+
+ if (cbaOld == NULL) { /* realloc wouldn't have copied from cbaDef */
+ memcpy(cba, cbaDef, curLen);
+ }
+ }
cba[ncbas].hp = thishost;
cba[ncbas].thead = cb->thead;
ncbas++;
}
if (ncbas) {
- MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
+ struct cbstruct *cba2;
+ int num;
- /* we need to to all these initializations again because MultiBreakCallBack may block */
- fe = FindFE(fid);
- if (!fe) {
- goto done;
- }
- cb = itocb(fe->firstcb);
- if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
- /* the most common case is what follows the || */
- goto done;
+ for (cba2 = cba, num = ncbas; ncbas > 0; cba2 += num, ncbas -= num) {
+ num = (ncbas > MAX_CB_HOSTS) ? MAX_CB_HOSTS : ncbas;
+ MultiBreakCallBack_r(cba2, num, &tf);
}
}
- }
+
+ if (cba != cbaDef) free(cba);
done:
H_UNLOCK;
return (host->hostFlags & VENUSDOWN);
}
-/*
-** 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(struct host *host, int isheld,
+MultiBreakVolumeCallBack_r(struct host *host,
struct VCBParams *parms, int deletefe)
{
char hoststr[16];
if (host->hostFlags & HOSTDELETED)
- return 0; /* host is deleted, release hold */
+ return 0;
if (!(host->hostFlags & HCBREAK))
return 0; /* host is not flagged to notify */
* later */
host->hostFlags &= ~(RESETDONE|HCBREAK); /* Do InitCallBackState when host returns */
h_Unlock_r(host);
- return 0; /* parent will release hold */
+ return 0;
}
- assert(parms->ncbas <= MAX_CB_HOSTS);
+ osi_Assert(parms->ncbas <= MAX_CB_HOSTS);
/* Do not call MultiBreakCallBack on the current host structure
** because it would prematurely release the hold on the host
tf.AFSCBFids_val = parms->fid;
/* this releases all the hosts */
- MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
+ MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf);
parms->ncbas = 0;
}
parms->cba[parms->ncbas].hp = host;
parms->cba[(parms->ncbas)++].thead = parms->thead;
host->hostFlags &= ~HCBREAK;
- return 1; /* parent shouldn't release hold, more work to do */
+
+ /* we have more work to do on this host, so make sure we keep a reference
+ * to it */
+ h_Hold_r(host);
+
+ return 0;
}
-/*
-** 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, void *rock)
+MultiBreakVolumeLaterCallBack(struct host *host, void *rock)
{
struct VCBParams *parms = (struct VCBParams *)rock;
int retval;
H_LOCK;
- retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
+ retval = MultiBreakVolumeCallBack_r(host, parms, 0);
H_UNLOCK;
return retval;
}
* Now uses multi-RX for CallBack RPC in a different thread,
* only marking them here.
*/
-#ifdef AFS_PTHREAD_ENV
extern pthread_cond_t fsync_cond;
-#else
-extern char fsync_wait[];
-#endif
int
BreakVolumeCallBacksLater(afs_uint32 volume)
}
ViceLog(25, ("Fsync thread wakeup\n"));
-#ifdef AFS_PTHREAD_ENV
FSYNC_LOCK;
- assert(pthread_cond_broadcast(&fsync_cond) == 0);
+ CV_BROADCAST(&fsync_cond);
FSYNC_UNLOCK;
-#else
- LWP_NoYieldSignal(fsync_wait);
-#endif
return 0;
}
tf.AFSCBFids_len = 1;
tf.AFSCBFids_val = &fid;
- MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
+ MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf);
henumParms.ncbas = 0;
}
}
* theory not give these to us anyway, but be paranoid.
*/
static int
-lih0_r(struct host *host, int flags, void *rock)
+lih0_r(struct host *host, void *rock)
{
struct lih_params *params = (struct lih_params *)rock;
h_Hold_r(host);
params->lih = host;
}
- return flags;
+ return 0;
}
/* same as lih0_r, except we do not prevent held hosts from being selected. */
static int
-lih1_r(struct host *host, int flags, void *rock)
+lih1_r(struct host *host, void *rock)
{
struct lih_params *params = (struct lih_params *)rock;
h_Hold_r(host);
params->lih = host;
}
- return flags;
+ return 0;
}
/* This could be upgraded to get more space each time */
struct lih_params params;
int i = 0;
+ if (cbstuff.GotSomeSpaces == 0) {
+ /* only log this once; if GSS is getting called constantly, that's not
+ * good but don't make things worse by spamming the log. */
+ ViceLog(0, ("We have run out of callback space; forcing callback revocation. "
+ "This suggests the fileserver is configured with insufficient "
+ "callbacks; you probably want to increase the -cb fileserver "
+ "parameter (current setting: %u). The fileserver will continue "
+ "to operate, but this may indicate a severe performance problem\n",
+ cbstuff.nblks));
+ ViceLog(0, ("This message is logged at most once; for more information "
+ "see the OpenAFS documentation and fileserver xstat collection 3\n"));
+ }
+
cbstuff.GotSomeSpaces++;
ViceLog(5,
("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
for (idx = 0; idx < niovecs; idx++) {
cbdsk = (struct CBDiskEntry *) iov[idx].iov_base;
+
+ if (cbdsk->cb.hhead < state->h_map.len &&
+ state->h_map.entries[cbdsk->cb.hhead].valid == FS_STATE_IDX_SKIPPED) {
+ continue;
+ }
+
if ((cb = GetCB()) == NULL) {
ViceLog(0, ("cb_stateRestoreCBs: ran out of free CallBack structures\n"));
ret = 1;
ret = 1;
goto done;
}
+ state->fe_map.entries[in->index].valid = FS_STATE_IDX_VALID;
state->fe_map.entries[in->index].old_idx = in->index;
state->fe_map.entries[in->index].new_idx = fetoi(out);
ret = 1;
goto done;
}
+ state->cb_map.entries[in->index].valid = FS_STATE_IDX_VALID;
state->cb_map.entries[in->index].old_idx = in->index;
state->cb_map.entries[in->index].new_idx = cbtoi(out);
if (old >= state->fe_map.len) {
ViceLog(0, ("fe_OldToNew: index %d is out of range\n", old));
ret = 1;
- } else if (state->fe_map.entries[old].old_idx != old) { /* sanity check */
+ } else if (state->fe_map.entries[old].valid != FS_STATE_IDX_VALID ||
+ state->fe_map.entries[old].old_idx != old) { /* sanity check */
ViceLog(0, ("fe_OldToNew: index %d points to an invalid FileEntry record\n", old));
ret = 1;
} else {
if (old >= state->cb_map.len) {
ViceLog(0, ("cb_OldToNew: index %d is out of range\n", old));
ret = 1;
- } else if (state->cb_map.entries[old].old_idx != old) { /* sanity check */
+ } else if (state->cb_map.entries[old].valid != FS_STATE_IDX_VALID ||
+ state->cb_map.entries[old].old_idx != old) { /* sanity check */
ViceLog(0, ("cb_OldToNew: index %d points to an invalid CallBack record\n", old));
ret = 1;
} else {
int fd, oflag;
afs_uint32 magic, freelisthead;
afs_uint32 now;
-#ifdef AFS_64BIT_ENV
afs_int64 now64;
-#endif
oflag = O_RDONLY;
#ifdef AFS_NT40_ENV
exit(1);
}
}
-#ifdef AFS_64BIT_ENV
if (timebits == 64) {
read(fd, &now64, sizeof(afs_int64));
now = (afs_int32) now64;
} else
-#endif
read(fd, &now, sizeof(afs_int32));
+
read(fd, &cbstuff, sizeof(cbstuff));
read(fd, TimeOuts, sizeof(TimeOuts));
read(fd, timeout, sizeof(timeout));
argc--;
timebits = atoi(*++argv);
if ((timebits != 32)
-#ifdef AFS_64BIT_ENV
&& (timebits != 64)
-#endif
)
err++;
} else if (!strcmp(*argv, "-volume")) {
if (err || argc != 1) {
fprintf(stderr,
"Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] [-timebits 32"
-#ifdef AFS_64BIT_ENV
"|64"
-#endif
"] callbackdumpfile\n");
fprintf(stderr,
"[cbid is shown for each host in the hosts.dump file]\n");
interfaces = calloc(i, sizeof(struct AddrPort));
conns = calloc(i, sizeof(struct rx_connection *));
if (!interfaces || !conns) {
- ViceLog(0,
- ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
- assert(0);
+ ViceLogThenPanic(0, ("Failed malloc in "
+ "MultiBreakCallBackAlternateAddress_r\n"));
}
/* initialize alternate rx connections */
j++;
}
- assert(j); /* at least one alternate address */
+ osi_Assert(j); /* at least one alternate address */
ViceLog(125,
("Starting multibreakcall back on all addr for host %p (%s:%d)\n",
host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
if (host->callback_rxcon)
rx_DestroyConnection(host->callback_rxcon);
host->callback_rxcon = conns[multi_i];
- h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
+ /* add then remove */
+ addInterfaceAddr_r(host, interfaces[multi_i].addr,
+ interfaces[multi_i].port);
+ removeInterfaceAddr_r(host, host->host, host->port);
host->host = interfaces[multi_i].addr;
host->port = interfaces[multi_i].port;
- h_AddHostToAddrHashTable_r(host->host, host->port, host);
connSuccess = conns[multi_i];
rx_SetConnDeadTime(host->callback_rxcon, 50);
rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
interfaces = calloc(i, sizeof(struct AddrPort));
conns = calloc(i, sizeof(struct rx_connection *));
if (!interfaces || !conns) {
- ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
- assert(0);
+ ViceLogThenPanic(0, ("Failed malloc in "
+ "MultiProbeAlternateAddress_r\n"));
}
/* initialize alternate rx connections */
j++;
}
- assert(j); /* at least one alternate address */
+ osi_Assert(j); /* at least one alternate address */
ViceLog(125,
("Starting multiprobe on all addr for host %p (%s:%d)\n",
host, afs_inet_ntoa_r(host->host, hoststr),
if (host->callback_rxcon)
rx_DestroyConnection(host->callback_rxcon);
host->callback_rxcon = conns[multi_i];
- h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
+ /* add then remove */
+ addInterfaceAddr_r(host, interfaces[multi_i].addr,
+ interfaces[multi_i].port);
+ removeInterfaceAddr_r(host, host->host, host->port);
host->host = interfaces[multi_i].addr;
host->port = interfaces[multi_i].port;
- h_AddHostToAddrHashTable_r(host->host, host->port, host);
connSuccess = conns[multi_i];
rx_SetConnDeadTime(host->callback_rxcon, 50);
rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);