#include <sys/file.h>
#endif
+#include <afs/opr.h>
+#include <opr/lock.h>
#include <afs/nfs.h> /* yuck. This is an abomination. */
-#include <lwp.h>
#include <rx/rx.h>
+#include <rx/rx_queue.h>
#include <afs/afscbint.h>
#include <afs/afsutil.h>
-#include <lock.h>
#include <afs/ihandle.h>
+#include <afs/partition.h>
#include <afs/vnode.h>
#include <afs/volume.h>
#include "viced_prototypes.h"
while (*p && *p != fei)
p = &itofe(*p)->fnext;
- osi_Assert(*p);
+ opr_Assert(*p);
*p = fe->fnext;
FreeFE(fe);
return 0;
int
InitCallBack(int nblks)
{
+ opr_Assert(nblks > 0);
+
H_LOCK;
- tfirst = CBtime(FT_ApproxTime());
+ tfirst = CBtime(time(NULL));
/* N.B. The "-1", below, is because
* FE[0] and CB[0] are not used--and not allocated */
- FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry))));
+ FE = calloc(nblks, sizeof(struct FileEntry));
if (!FE) {
ViceLogThenPanic(0, ("Failed malloc in InitCallBack\n"));
}
cbstuff.nFEs = nblks;
while (cbstuff.nFEs)
FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
- CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack))));
+ CB = calloc(nblks, sizeof(struct CallBack));
if (!CB) {
ViceLogThenPanic(0, ("Failed malloc in InitCallBack\n"));
}
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;
fe = FindFE(fid);
if (type == CB_NORMAL) {
time_out =
- TimeCeiling(FT_ApproxTime() + TimeOut(fe ? fe->ncbs : 0) +
+ TimeCeiling(time(NULL) + TimeOut(fe ? fe->ncbs : 0) +
ServerBias);
Thead = THead(CBtime(time_out));
} else if (type == CB_VOLUME) {
- time_out = TimeCeiling((60 * 120 + FT_ApproxTime()) + ServerBias);
+ time_out = TimeCeiling((60 * 120 + time(NULL)) + ServerBias);
Thead = THead(CBtime(time_out));
} else if (type == CB_BULK) {
/* bulk status can get so many callbacks all at once, and most of them
* are probably not for things that will be used for long.
*/
time_out =
- TimeCeiling(FT_ApproxTime() + ServerBias +
+ TimeCeiling(time(NULL) + ServerBias +
TimeOut(22 + (fe ? fe->ncbs : 0)));
Thead = THead(CBtime(time_out));
}
static struct AFSCBs tc = { 0, 0 };
int multi_to_cba_map[MAX_CB_HOSTS];
- osi_Assert(ncbas <= MAX_CB_HOSTS);
-
- /* sort cba list to avoid makecall issues */
+ opr_Assert(ncbas <= MAX_CB_HOSTS);
+
+ /*
+ * When we issue a multi_Rx callback break, we must rx_NewCall a call for
+ * each host before we do anything. If there are no call channels
+ * available on the conn, we must wait for one of the existing calls to
+ * finish. If another thread is breaking callbacks at the same time, it is
+ * possible for us to be waiting on NewCall for one of their multi_Rx
+ * CallBack calls to finish, but they are waiting on NewCall for one of
+ * our calls to finish. So we deadlock.
+ *
+ * This can be thought of as similar to obtaining multiple locks at the
+ * same time. So if we establish an ordering, the possibility of deadlock
+ * goes away. Here we provide such an ordering, by sorting our CBAs
+ * according to CompareCBA.
+ */
qsort(cba, ncbas, sizeof(struct cbstruct), CompareCBA);
/* set up conns for multi-call */
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? */
{
struct FileEntry *fe;
struct CallBack *cb, *nextcb;
- struct cbstruct cbaDef[MAX_CB_HOSTS], *cba = cbaDef;
- unsigned int ncbas, cbaAlloc = MAX_CB_HOSTS;
+ struct cbstruct cba[MAX_CB_HOSTS];
+ int ncbas;
struct AFSCBFids tf;
int hostindex;
char hoststr[16];
tf.AFSCBFids_len = 1;
tf.AFSCBFids_val = fid;
- for (ncbas = 0; cb ; cb = nextcb) {
+ for (; cb;) {
+ for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; 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) {
- struct cbstruct *cba2;
- int num;
+ MultiBreakCallBack_r(cba, ncbas, &tf);
- 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);
+ /* 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;
}
}
-
- if (cba != cbaDef) free(cba);
+ }
done:
H_UNLOCK;
h_Unlock_r(host);
return 0;
}
- osi_Assert(parms->ncbas <= MAX_CB_HOSTS);
+ opr_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
extern pthread_cond_t fsync_cond;
int
-BreakVolumeCallBacksLater(afs_uint32 volume)
+BreakVolumeCallBacksLater(VolumeId volume)
{
int hash;
afs_uint32 *feip;
struct host *host;
int found = 0;
- ViceLog(25, ("Setting later on volume %u\n", volume));
+ ViceLog(25, ("Setting later on volume %" AFS_VOLID_FMT "\n",
+ afs_printable_VolumeId_lu(volume)));
H_LOCK;
for (hash = 0; hash < FEHASH_SIZE; hash++) {
for (feip = &HashTable[hash]; (fe = itofe(*feip)) != NULL; ) {
ViceLog(25, ("Fsync thread wakeup\n"));
FSYNC_LOCK;
- CV_BROADCAST(&fsync_cond);
+ opr_cv_broadcast(&fsync_cond);
FSYNC_UNLOCK;
return 0;
}
/* Ugly, but used to avoid left side casting */
struct object *tmpfe;
ViceLog(125,
- ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
- fe->volid));
+ ("Unchaining for %u:%u:%" AFS_VOLID_FMT "\n", fe->vnode,
+ fe->unique, afs_printable_VolumeId_lu(fe->volid)));
fid.Volume = fe->volid;
*feip = fe->fnext;
fe->status &= ~FE_LATER; /* not strictly needed */
/* leave flag for MultiBreakVolumeCallBack to clear */
} else {
ViceLog(125,
- ("Found host %p (%s:%d) non-DELAYED cb for %u:%u:%u\n",
+ ("Found host %p (%s:%d) non-DELAYED cb for %u:%u:%" AFS_VOLID_FMT "\n",
host, afs_inet_ntoa_r(host->host, hoststr),
- ntohs(host->port), fe->vnode, fe->unique, fe->volid));
+ ntohs(host->port), fe->vnode, fe->unique,
+ afs_printable_VolumeId_lu(fe->volid)));
}
}
myfe = fe;
int
CleanupTimedOutCallBacks_r(void)
{
- afs_uint32 now = CBtime(FT_ApproxTime());
+ afs_uint32 now = CBtime(time(NULL));
afs_uint32 *thead;
struct CallBack *cb;
int ntimedout = 0;
cb = itocb(cbi);
cbi = cb->tnext;
ViceLog(8,
- ("CCB: deleting timed out call back %x (%s:%d), (%u,%u,%u)\n",
+ ("CCB: deleting timed out call back %x (%s:%d), (%" AFS_VOLID_FMT ",%u,%u)\n",
h_itoh(cb->hhead)->host,
afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
- h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
+ h_itoh(cb->hhead)->port,
+ afs_printable_VolumeId_lu(itofe(cb->fhead)->volid),
itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
HDel(cb);
CDel(cb, 1);
}
#endif /* AFS_DEMAND_ATTACH_FS */
+#define DumpBytes(fd,buf,req) if (write(fd, buf, req) < 0) ; /* don't care */
+
static int
DumpCallBackState_r(void)
{
int fd, oflag;
- afs_uint32 magic = MAGICV2, now = (afs_int32) FT_ApproxTime(), freelisthead;
+ afs_uint32 magic = MAGICV2, now = (afs_int32) time(NULL), freelisthead;
oflag = O_WRONLY | O_CREAT | O_TRUNC;
#ifdef AFS_NT40_ENV
AFSDIR_SERVER_CBKDUMP_FILEPATH));
return 0;
}
- (void)write(fd, &magic, sizeof(magic));
- (void)write(fd, &now, sizeof(now));
- (void)write(fd, &cbstuff, sizeof(cbstuff));
- (void)write(fd, TimeOuts, sizeof(TimeOuts));
- (void)write(fd, timeout, sizeof(timeout));
- (void)write(fd, &tfirst, sizeof(tfirst));
+ /*
+ * Collect but ignoring the return value of write(2) here,
+ * to avoid compiler warnings on some platforms.
+ */
+ DumpBytes(fd, &magic, sizeof(magic));
+ DumpBytes(fd, &now, sizeof(now));
+ DumpBytes(fd, &cbstuff, sizeof(cbstuff));
+ DumpBytes(fd, TimeOuts, sizeof(TimeOuts));
+ DumpBytes(fd, timeout, sizeof(timeout));
+ DumpBytes(fd, &tfirst, sizeof(tfirst));
freelisthead = cbtoi((struct CallBack *)CBfree);
- (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
+ DumpBytes(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
freelisthead = fetoi((struct FileEntry *)FEfree);
- (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
- (void)write(fd, HashTable, sizeof(HashTable));
- (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
- (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
+ DumpBytes(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
+ DumpBytes(fd, HashTable, sizeof(HashTable));
+ DumpBytes(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
+ DumpBytes(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
close(fd);
return 0;
#ifdef INTERPRET_DUMP
+static void
+ReadBytes(int fd, void *buf, size_t req)
+{
+ ssize_t count;
+
+ count = read(fd, buf, req);
+ if (count < 0) {
+ perror("read");
+ exit(-1);
+ } else if (count != req) {
+ fprintf(stderr, "read: premature EOF (expected %lu, got %lu)\n",
+ (unsigned long)req, (unsigned long)count);
+ exit(-1);
+ }
+}
+
/* This is only compiled in for the callback analyzer program */
/* Returns the time of the dump */
time_t
fprintf(stderr, "Couldn't read dump file %s\n", file);
exit(1);
}
- read(fd, &magic, sizeof(magic));
+ ReadBytes(fd, &magic, sizeof(magic));
if (magic == MAGICV2) {
timebits = 32;
} else {
}
}
if (timebits == 64) {
- read(fd, &now64, sizeof(afs_int64));
+ ReadBytes(fd, &now64, sizeof(afs_int64));
now = (afs_int32) now64;
} else
- read(fd, &now, sizeof(afs_int32));
+ ReadBytes(fd, &now, sizeof(afs_int32));
- read(fd, &cbstuff, sizeof(cbstuff));
- read(fd, TimeOuts, sizeof(TimeOuts));
- read(fd, timeout, sizeof(timeout));
- read(fd, &tfirst, sizeof(tfirst));
- read(fd, &freelisthead, sizeof(freelisthead));
+ ReadBytes(fd, &cbstuff, sizeof(cbstuff));
+ ReadBytes(fd, TimeOuts, sizeof(TimeOuts));
+ ReadBytes(fd, timeout, sizeof(timeout));
+ ReadBytes(fd, &tfirst, sizeof(tfirst));
+ ReadBytes(fd, &freelisthead, sizeof(freelisthead));
CB = ((struct CallBack
*)(calloc(cbstuff.nblks, sizeof(struct CallBack)))) - 1;
FE = ((struct FileEntry
*)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
CBfree = (struct CallBack *)itocb(freelisthead);
- read(fd, &freelisthead, sizeof(freelisthead));
+ ReadBytes(fd, &freelisthead, sizeof(freelisthead));
FEfree = (struct FileEntry *)itofe(freelisthead);
- read(fd, HashTable, sizeof(HashTable));
- read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
- read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
+ ReadBytes(fd, HashTable, sizeof(HashTable));
+ ReadBytes(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
+ ReadBytes(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
if (close(fd)) {
perror("Error reading dumpfile");
exit(1);
if (fe == NULL)
return;
- printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %lu secs at %s",
- fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
- expires - now, ctime(&expires));
+ printf("vol=%" AFS_VOLID_FMT " vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %lu secs at %s",
+ afs_printable_VolumeId_lu(fe->volid), fe->vnode, fe->ncbs,
+ cb->hhead, cb->status, fe->status, expires - now, ctime(&expires));
}
#endif
j++;
}
- osi_Assert(j); /* at least one alternate address */
+ opr_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);
j++;
}
- osi_Assert(j); /* at least one alternate address */
+ opr_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);