#include "sys/types.h"
#include <sys/stat.h>
#include <errno.h>
-#if defined(AFS_NT40_ENV) || defined(AFS_DJGPP_ENV)
+#if defined(AFS_NT40_ENV)
#ifdef AFS_NT40_ENV
#include <winsock2.h>
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif /* AFS_NT40_ENV */
+#include "rx_user.h"
#include "rx_xmit_nt.h"
#include <stdlib.h>
#else
#include "rx_globals.h"
#include <lwp.h>
#include <assert.h>
-#ifdef HAVE_STRING_H
#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
extern char cml_version_number[];
extern int (*rx_almostSent) ();
+static int AllocPacketBufs(int class, int num_pkts, struct rx_queue *q);
+
static void rxi_SendDebugPacket(struct rx_packet *apacket, osi_socket asocket,
afs_int32 ahost, short aport,
afs_int32 istack);
+static int rxi_FreeDataBufsToQueue(struct rx_packet *p,
+ afs_uint32 first,
+ struct rx_queue * q);
+static int
+rxi_FreeDataBufsTSFPQ(struct rx_packet *p, afs_uint32 first, int flush_global);
+
+
/* some rules about packets:
* 1. When a packet is allocated, the final iov_buf contains room for
* a security trailer, but iov_len masks that fact. If the security
/* i is the iovec which contains the first little bit of data in which we
* are interested. l is the total length of everything prior to this iovec.
* j is the number of bytes we can safely copy out of this iovec.
+ * offset only applies to the first iovec.
*/
r = resid;
while ((resid > 0) && (i < packet->niovecs)) {
j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
memcpy(out, (char *)(packet->wirevec[i].iov_base) + (offset - l), j);
resid -= j;
- l += packet->wirevec[i].iov_len;
+ out += j;
+ l += packet->wirevec[i].iov_len;
+ offset = l;
i++;
}
/* i is the iovec which contains the first little bit of data in which we
* are interested. l is the total length of everything prior to this iovec.
* j is the number of bytes we can safely copy out of this iovec.
+ * offset only applies to the first iovec.
*/
r = resid;
while ((resid > 0) && (i < RX_MAXWVECS)) {
j = MIN(resid, packet->wirevec[i].iov_len - (offset - l));
memcpy(b, in, j);
resid -= j;
+ in += j;
l += packet->wirevec[i].iov_len;
+ offset = l;
i++;
}
return (resid ? (r - resid) : r);
}
-static struct rx_packet *
-allocCBuf(int class)
+int
+rxi_AllocPackets(int class, int num_pkts, struct rx_queue * q)
+{
+ register struct rx_packet *p, *np;
+
+ num_pkts = AllocPacketBufs(class, num_pkts, q);
+
+ for (queue_Scan(q, p, np, rx_packet)) {
+ RX_PACKET_IOV_FULLINIT(p);
+ }
+
+ return num_pkts;
+}
+
+#ifdef RX_ENABLE_TSFPQ
+static int
+AllocPacketBufs(int class, int num_pkts, struct rx_queue * q)
+{
+ register struct rx_ts_info_t * rx_ts_info;
+ int transfer, alloc;
+ SPLVAR;
+
+ RX_TS_INFO_GET(rx_ts_info);
+
+ transfer = num_pkts - rx_ts_info->_FPQ.len;
+ if (transfer > 0) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ if ((transfer + rx_TSFPQGlobSize) <= rx_nFreePackets) {
+ transfer += rx_TSFPQGlobSize;
+ } else if (transfer <= rx_nFreePackets) {
+ transfer = rx_nFreePackets;
+ } else {
+ /* alloc enough for us, plus a few globs for other threads */
+ alloc = transfer + (3 * rx_TSFPQGlobSize) - rx_nFreePackets;
+ rxi_MorePacketsNoLock(MAX(alloc, rx_initSendWindow));
+ transfer += rx_TSFPQGlobSize;
+ }
+
+ RX_TS_FPQ_GTOL2(rx_ts_info, transfer);
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+
+ RX_TS_FPQ_QCHECKOUT(rx_ts_info, num_pkts, q);
+
+ return num_pkts;
+}
+#else /* RX_ENABLE_TSFPQ */
+static int
+AllocPacketBufs(int class, int num_pkts, struct rx_queue * q)
{
struct rx_packet *c;
+ int i, overq = 0;
SPLVAR;
NETPRI;
+
MUTEX_ENTER(&rx_freePktQ_lock);
#ifdef KERNEL
- if (rxi_OverQuota(class)) {
- c = NULL;
+ for (; (num_pkts > 0) && (rxi_OverQuota2(class,num_pkts));
+ num_pkts--, overq++);
+
+ if (overq) {
rxi_NeedMorePackets = TRUE;
- MUTEX_ENTER(&rx_stats_mutex);
switch (class) {
case RX_PACKET_CLASS_RECEIVE:
- rx_stats.receivePktAllocFailures++;
+ rx_MutexIncrement(rx_stats.receivePktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_SEND:
- rx_stats.sendPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.sendPktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_SPECIAL:
- rx_stats.specialPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.specialPktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_RECV_CBUF:
- rx_stats.receiveCbufPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.receiveCbufPktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_SEND_CBUF:
- rx_stats.sendCbufPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.sendCbufPktAllocFailures, rx_stats_mutex);
break;
}
- MUTEX_EXIT(&rx_stats_mutex);
- goto done;
}
- if (queue_IsEmpty(&rx_freePacketQueue)) {
- c = NULL;
+ if (rx_nFreePackets < num_pkts)
+ num_pkts = rx_nFreePackets;
+
+ if (!num_pkts) {
rxi_NeedMorePackets = TRUE;
goto done;
}
#else /* KERNEL */
- if (queue_IsEmpty(&rx_freePacketQueue)) {
- rxi_MorePacketsNoLock(rx_initSendWindow);
+ if (rx_nFreePackets < num_pkts) {
+ rxi_MorePacketsNoLock(MAX((num_pkts-rx_nFreePackets), rx_initSendWindow));
}
#endif /* KERNEL */
- rx_nFreePackets--;
- c = queue_First(&rx_freePacketQueue, rx_packet);
- queue_Remove(c);
- if (!(c->flags & RX_PKTFLAG_FREE))
- osi_Panic("rxi_AllocPacket: packet not free\n");
- c->flags = 0; /* clear RX_PKTFLAG_FREE, initialize the rest */
- c->header.flags = 0;
+ for (i=0, c=queue_First(&rx_freePacketQueue, rx_packet);
+ i < num_pkts;
+ i++, c=queue_Next(c, rx_packet)) {
+ RX_FPQ_MARK_USED(c);
+ }
+
+ queue_SplitBeforeAppend(&rx_freePacketQueue,q,c);
+
+ rx_nFreePackets -= num_pkts;
#ifdef KERNEL
done:
MUTEX_EXIT(&rx_freePktQ_lock);
USERPRI;
- return c;
+ return num_pkts;
}
+#endif /* RX_ENABLE_TSFPQ */
/*
* Free a packet currently used as a continuation buffer
*/
-void
-rxi_freeCBuf(struct rx_packet *c)
+#ifdef RX_ENABLE_TSFPQ
+/* num_pkts=0 means queue length is unknown */
+int
+rxi_FreePackets(int num_pkts, struct rx_queue * q)
+{
+ register struct rx_ts_info_t * rx_ts_info;
+ register struct rx_packet *c, *nc;
+ SPLVAR;
+
+ osi_Assert(num_pkts >= 0);
+ RX_TS_INFO_GET(rx_ts_info);
+
+ if (!num_pkts) {
+ for (queue_Scan(q, c, nc, rx_packet), num_pkts++) {
+ rxi_FreeDataBufsTSFPQ(c, 2, 0);
+ }
+ } else {
+ for (queue_Scan(q, c, nc, rx_packet)) {
+ rxi_FreeDataBufsTSFPQ(c, 2, 0);
+ }
+ }
+
+ if (num_pkts) {
+ RX_TS_FPQ_QCHECKIN(rx_ts_info, num_pkts, q);
+ }
+
+ if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ RX_TS_FPQ_LTOG(rx_ts_info);
+
+ /* Wakeup anyone waiting for packets */
+ rxi_PacketsUnWait();
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+
+ return num_pkts;
+}
+#else /* RX_ENABLE_TSFPQ */
+/* num_pkts=0 means queue length is unknown */
+int
+rxi_FreePackets(int num_pkts, struct rx_queue *q)
{
+ struct rx_queue cbs;
+ register struct rx_packet *p, *np;
+ int qlen = 0;
SPLVAR;
+ osi_Assert(num_pkts >= 0);
+ queue_Init(&cbs);
+
+ if (!num_pkts) {
+ for (queue_Scan(q, p, np, rx_packet), num_pkts++) {
+ if (p->niovecs > 2) {
+ qlen += rxi_FreeDataBufsToQueue(p, 2, &cbs);
+ }
+ RX_FPQ_MARK_FREE(p);
+ }
+ if (!num_pkts)
+ return 0;
+ } else {
+ for (queue_Scan(q, p, np, rx_packet)) {
+ if (p->niovecs > 2) {
+ qlen += rxi_FreeDataBufsToQueue(p, 2, &cbs);
+ }
+ RX_FPQ_MARK_FREE(p);
+ }
+ }
+
+ if (qlen) {
+ queue_SpliceAppend(q, &cbs);
+ qlen += num_pkts;
+ } else
+ qlen = num_pkts;
+
NETPRI;
MUTEX_ENTER(&rx_freePktQ_lock);
- rxi_FreePacketNoLock(c);
+ queue_SpliceAppend(&rx_freePacketQueue, q);
+ rx_nFreePackets += qlen;
+
/* Wakeup anyone waiting for packets */
rxi_PacketsUnWait();
MUTEX_EXIT(&rx_freePktQ_lock);
USERPRI;
+
+ return num_pkts;
}
+#endif /* RX_ENABLE_TSFPQ */
/* this one is kind of awful.
* In rxkad, the packet has been all shortened, and everything, ready for
* returns the number of bytes >0 which it failed to come up with.
* Don't need to worry about locking on packet, since only
* one thread can manipulate one at a time. Locking on continution
- * packets is handled by allocCBuf */
+ * packets is handled by AllocPacketBufs */
/* MTUXXX don't need to go throught the for loop if we can trust niovecs */
int
rxi_AllocDataBuf(struct rx_packet *p, int nb, int class)
{
- int i;
-
- for (i = p->niovecs; nb > 0 && i < RX_MAXWVECS; i++) {
- register struct rx_packet *cb;
- if ((cb = allocCBuf(class))) {
- p->wirevec[i].iov_base = (caddr_t) cb->localdata;
- p->wirevec[i].iov_len = RX_CBUFFERSIZE;
- nb -= RX_CBUFFERSIZE;
- p->length += RX_CBUFFERSIZE;
- p->niovecs++;
- } else
- break;
+ int i, nv;
+ struct rx_queue q;
+ register struct rx_packet *cb, *ncb;
+
+ /* compute the number of cbuf's we need */
+ nv = nb / RX_CBUFFERSIZE;
+ if ((nv * RX_CBUFFERSIZE) < nb)
+ nv++;
+ if ((nv + p->niovecs) > RX_MAXWVECS)
+ nv = RX_MAXWVECS - p->niovecs;
+ if (nv < 1)
+ return nb;
+
+ /* allocate buffers */
+ queue_Init(&q);
+ nv = AllocPacketBufs(class, nv, &q);
+
+ /* setup packet iovs */
+ for (i = p->niovecs, queue_Scan(&q, cb, ncb, rx_packet), i++) {
+ queue_Remove(cb);
+ p->wirevec[i].iov_base = (caddr_t) cb->localdata;
+ p->wirevec[i].iov_len = RX_CBUFFERSIZE;
}
+ nb -= (nv * RX_CBUFFERSIZE);
+ p->length += (nv * RX_CBUFFERSIZE);
+ p->niovecs += nv;
+
return nb;
}
/* Add more packet buffers */
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_MorePackets(int apackets)
+{
+ struct rx_packet *p, *e;
+ register struct rx_ts_info_t * rx_ts_info;
+ int getme;
+ SPLVAR;
+
+ getme = apackets * sizeof(struct rx_packet);
+ p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
+
+ PIN(p, getme); /* XXXXX */
+ memset((char *)p, 0, getme);
+ RX_TS_INFO_GET(rx_ts_info);
+
+ for (e = p + apackets; p < e; p++) {
+ RX_PACKET_IOV_INIT(p);
+ p->niovecs = 2;
+
+ RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+ }
+ rx_ts_info->_FPQ.delta += apackets;
+
+ if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ RX_TS_FPQ_LTOG(rx_ts_info);
+ rxi_NeedMorePackets = FALSE;
+ rxi_PacketsUnWait();
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+}
+#else /* RX_ENABLE_TSFPQ */
void
rxi_MorePackets(int apackets)
{
PIN(p, getme); /* XXXXX */
memset((char *)p, 0, getme);
NETPRI;
- AFS_RXGLOCK();
MUTEX_ENTER(&rx_freePktQ_lock);
for (e = p + apackets; p < e; p++) {
- p->wirevec[0].iov_base = (char *)(p->wirehead);
- p->wirevec[0].iov_len = RX_HEADER_SIZE;
- p->wirevec[1].iov_base = (char *)(p->localdata);
- p->wirevec[1].iov_len = RX_FIRSTBUFFERSIZE;
+ RX_PACKET_IOV_INIT(p);
p->flags |= RX_PKTFLAG_FREE;
p->niovecs = 2;
rxi_NeedMorePackets = FALSE;
rxi_PacketsUnWait();
- AFS_RXGUNLOCK();
MUTEX_EXIT(&rx_freePktQ_lock);
USERPRI;
}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_MorePacketsTSFPQ(int apackets, int flush_global, int num_keep_local)
+{
+ struct rx_packet *p, *e;
+ register struct rx_ts_info_t * rx_ts_info;
+ int getme;
+ SPLVAR;
+
+ getme = apackets * sizeof(struct rx_packet);
+ p = rx_mallocedP = (struct rx_packet *)osi_Alloc(getme);
+
+ PIN(p, getme); /* XXXXX */
+ memset((char *)p, 0, getme);
+ RX_TS_INFO_GET(rx_ts_info);
+
+ for (e = p + apackets; p < e; p++) {
+ RX_PACKET_IOV_INIT(p);
+ p->niovecs = 2;
+
+ RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+ }
+ rx_ts_info->_FPQ.delta += apackets;
+
+ if (flush_global &&
+ (num_keep_local < apackets)) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ RX_TS_FPQ_LTOG2(rx_ts_info, (apackets - num_keep_local));
+ rxi_NeedMorePackets = FALSE;
+ rxi_PacketsUnWait();
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+}
+#endif /* RX_ENABLE_TSFPQ */
#ifndef KERNEL
/* Add more packet buffers */
memset((char *)p, 0, getme);
for (e = p + apackets; p < e; p++) {
- p->wirevec[0].iov_base = (char *)(p->wirehead);
- p->wirevec[0].iov_len = RX_HEADER_SIZE;
- p->wirevec[1].iov_base = (char *)(p->localdata);
- p->wirevec[1].iov_len = RX_FIRSTBUFFERSIZE;
+ RX_PACKET_IOV_INIT(p);
p->flags |= RX_PKTFLAG_FREE;
p->niovecs = 2;
queue_Append(&rx_freePacketQueue, p);
}
+
rx_nFreePackets += apackets;
+#ifdef RX_ENABLE_TSFPQ
+ /* TSFPQ patch also needs to keep track of total packets */
+ MUTEX_ENTER(&rx_stats_mutex);
+ rx_nPackets += apackets;
+ RX_TS_FPQ_COMPUTE_LIMITS;
+ MUTEX_EXIT(&rx_stats_mutex);
+#endif /* RX_ENABLE_TSFPQ */
rxi_NeedMorePackets = FALSE;
rxi_PacketsUnWait();
}
UNPIN(rx_mallocedP, (rx_maxReceiveWindow + 2) * sizeof(struct rx_packet));
}
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_AdjustLocalPacketsTSFPQ(int num_keep_local, int allow_overcommit)
+{
+ register struct rx_ts_info_t * rx_ts_info;
+ register int xfer;
+ SPLVAR;
+
+ RX_TS_INFO_GET(rx_ts_info);
+
+ if (num_keep_local != rx_ts_info->_FPQ.len) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+ if (num_keep_local < rx_ts_info->_FPQ.len) {
+ xfer = rx_ts_info->_FPQ.len - num_keep_local;
+ RX_TS_FPQ_LTOG2(rx_ts_info, xfer);
+ rxi_PacketsUnWait();
+ } else {
+ xfer = num_keep_local - rx_ts_info->_FPQ.len;
+ if ((num_keep_local > rx_TSFPQLocalMax) && !allow_overcommit)
+ xfer = rx_TSFPQLocalMax - rx_ts_info->_FPQ.len;
+ if (rx_nFreePackets < xfer) {
+ rxi_MorePacketsNoLock(xfer - rx_nFreePackets);
+ }
+ RX_TS_FPQ_GTOL2(rx_ts_info, xfer);
+ }
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+}
+
+void
+rxi_FlushLocalPacketsTSFPQ(void)
+{
+ rxi_AdjustLocalPacketsTSFPQ(0, 0);
+}
+#endif /* RX_ENABLE_TSFPQ */
+
/* Allocate more packets iff we need more continuation buffers */
/* In kernel, can't page in memory with interrupts disabled, so we
* don't use the event mechanism. */
*/
/* Actually free the packet p. */
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_FreePacketNoLock(struct rx_packet *p)
+{
+ register struct rx_ts_info_t * rx_ts_info;
+ dpf(("Free %lx\n", (unsigned long)p));
+
+ RX_TS_INFO_GET(rx_ts_info);
+ RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+ if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+ RX_TS_FPQ_LTOG(rx_ts_info);
+ }
+}
+#else /* RX_ENABLE_TSFPQ */
void
rxi_FreePacketNoLock(struct rx_packet *p)
{
- dpf(("Free %x\n", (int)p));
+ dpf(("Free %lx\n", (unsigned long)p));
- if (p->flags & RX_PKTFLAG_FREE)
- osi_Panic("rxi_FreePacketNoLock: packet already free\n");
+ RX_FPQ_MARK_FREE(p);
rx_nFreePackets++;
- p->flags |= RX_PKTFLAG_FREE;
queue_Append(&rx_freePacketQueue, p);
}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_FreePacketTSFPQ(struct rx_packet *p, int flush_global)
+{
+ register struct rx_ts_info_t * rx_ts_info;
+ dpf(("Free %lx\n", (unsigned long)p));
+
+ RX_TS_INFO_GET(rx_ts_info);
+ RX_TS_FPQ_CHECKIN(rx_ts_info,p);
+
+ if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ RX_TS_FPQ_LTOG(rx_ts_info);
+
+ /* Wakeup anyone waiting for packets */
+ rxi_PacketsUnWait();
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+}
+#endif /* RX_ENABLE_TSFPQ */
+
+/*
+ * free continuation buffers off a packet into a queue
+ *
+ * [IN] p -- packet from which continuation buffers will be freed
+ * [IN] first -- iovec offset of first continuation buffer to free
+ * [IN] q -- queue into which continuation buffers will be chained
+ *
+ * returns:
+ * number of continuation buffers freed
+ */
+static int
+rxi_FreeDataBufsToQueue(struct rx_packet *p, afs_uint32 first, struct rx_queue * q)
+{
+ struct iovec *iov;
+ struct rx_packet * cb;
+ int count = 0;
+
+ for (first = MAX(2, first); first < p->niovecs; first++, count++) {
+ iov = &p->wirevec[first];
+ if (!iov->iov_base)
+ osi_Panic("rxi_FreeDataBufsToQueue: unexpected NULL iov");
+ cb = RX_CBUF_TO_PACKET(iov->iov_base, p);
+ RX_FPQ_MARK_FREE(cb);
+ queue_Append(q, cb);
+ }
+ p->length = 0;
+ p->niovecs = 0;
+
+ return count;
+}
+
+/*
+ * free packet continuation buffers into the global free packet pool
+ *
+ * [IN] p -- packet from which to free continuation buffers
+ * [IN] first -- iovec offset of first continuation buffer to free
+ *
+ * returns:
+ * zero always
+ */
int
-rxi_FreeDataBufsNoLock(struct rx_packet *p, int first)
+rxi_FreeDataBufsNoLock(struct rx_packet *p, afs_uint32 first)
{
- struct iovec *iov, *end;
+ struct iovec *iov;
- if (first != 1) /* MTUXXX */
- osi_Panic("FreeDataBufs 1: first must be 1");
- iov = &p->wirevec[1];
- end = iov + (p->niovecs - 1);
- if (iov->iov_base != (caddr_t) p->localdata) /* MTUXXX */
- osi_Panic("FreeDataBufs 2: vec 1 must be localdata");
- for (iov++; iov < end; iov++) {
+ for (first = MAX(2, first); first < p->niovecs; first++) {
+ iov = &p->wirevec[first];
if (!iov->iov_base)
- osi_Panic("FreeDataBufs 3: vecs 2-niovecs must not be NULL");
+ osi_Panic("rxi_FreeDataBufsNoLock: unexpected NULL iov");
rxi_FreePacketNoLock(RX_CBUF_TO_PACKET(iov->iov_base, p));
}
p->length = 0;
return 0;
}
+#ifdef RX_ENABLE_TSFPQ
+/*
+ * free packet continuation buffers into the thread-local free pool
+ *
+ * [IN] p -- packet from which continuation buffers will be freed
+ * [IN] first -- iovec offset of first continuation buffer to free
+ * [IN] flush_global -- if nonzero, we will flush overquota packets to the
+ * global free pool before returning
+ *
+ * returns:
+ * zero always
+ */
+static int
+rxi_FreeDataBufsTSFPQ(struct rx_packet *p, afs_uint32 first, int flush_global)
+{
+ struct iovec *iov;
+ register struct rx_ts_info_t * rx_ts_info;
+
+ RX_TS_INFO_GET(rx_ts_info);
+
+ for (first = MAX(2, first); first < p->niovecs; first++) {
+ iov = &p->wirevec[first];
+ if (!iov->iov_base)
+ osi_Panic("rxi_FreeDataBufsTSFPQ: unexpected NULL iov");
+ RX_TS_FPQ_CHECKIN(rx_ts_info,RX_CBUF_TO_PACKET(iov->iov_base, p));
+ }
+ p->length = 0;
+ p->niovecs = 0;
+
+ if (flush_global && (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax)) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ RX_TS_FPQ_LTOG(rx_ts_info);
+
+ /* Wakeup anyone waiting for packets */
+ rxi_PacketsUnWait();
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+ return 0;
+}
+#endif /* RX_ENABLE_TSFPQ */
+
int rxi_nBadIovecs = 0;
/* rxi_RestoreDataBufs
int i;
struct iovec *iov = &p->wirevec[2];
- p->wirevec[0].iov_base = (char *)(p->wirehead);
- p->wirevec[0].iov_len = RX_HEADER_SIZE;
- p->wirevec[1].iov_base = (char *)(p->localdata);
- p->wirevec[1].iov_len = RX_FIRSTBUFFERSIZE;
+ RX_PACKET_IOV_INIT(p);
for (i = 2, iov = &p->wirevec[2]; i < p->niovecs; i++, iov++) {
if (!iov->iov_base) {
}
}
+#ifdef RX_ENABLE_TSFPQ
+int
+rxi_TrimDataBufs(struct rx_packet *p, int first)
+{
+ int length;
+ struct iovec *iov, *end;
+ register struct rx_ts_info_t * rx_ts_info;
+ SPLVAR;
+
+ if (first != 1)
+ osi_Panic("TrimDataBufs 1: first must be 1");
+
+ /* Skip over continuation buffers containing message data */
+ iov = &p->wirevec[2];
+ end = iov + (p->niovecs - 2);
+ length = p->length - p->wirevec[1].iov_len;
+ for (; iov < end && length > 0; iov++) {
+ if (!iov->iov_base)
+ osi_Panic("TrimDataBufs 3: vecs 1-niovecs must not be NULL");
+ length -= iov->iov_len;
+ }
+
+ /* iov now points to the first empty data buffer. */
+ if (iov >= end)
+ return 0;
+
+ RX_TS_INFO_GET(rx_ts_info);
+ for (; iov < end; iov++) {
+ if (!iov->iov_base)
+ osi_Panic("TrimDataBufs 4: vecs 2-niovecs must not be NULL");
+ RX_TS_FPQ_CHECKIN(rx_ts_info,RX_CBUF_TO_PACKET(iov->iov_base, p));
+ p->niovecs--;
+ }
+ if (rx_ts_info->_FPQ.len > rx_TSFPQLocalMax) {
+ NETPRI;
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ RX_TS_FPQ_LTOG(rx_ts_info);
+ rxi_PacketsUnWait();
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ USERPRI;
+ }
+
+ return 0;
+}
+#else /* RX_ENABLE_TSFPQ */
int
rxi_TrimDataBufs(struct rx_packet *p, int first)
{
return 0;
}
+#endif /* RX_ENABLE_TSFPQ */
/* Free the packet p. P is assumed not to be on any queue, i.e.
* remove it yourself first if you call this routine. */
+#ifdef RX_ENABLE_TSFPQ
+void
+rxi_FreePacket(struct rx_packet *p)
+{
+ rxi_FreeDataBufsTSFPQ(p, 2, 0);
+ rxi_FreePacketTSFPQ(p, RX_TS_FPQ_FLUSH_GLOBAL);
+}
+#else /* RX_ENABLE_TSFPQ */
void
rxi_FreePacket(struct rx_packet *p)
{
NETPRI;
MUTEX_ENTER(&rx_freePktQ_lock);
- rxi_FreeDataBufsNoLock(p, 1);
+ rxi_FreeDataBufsNoLock(p, 2);
rxi_FreePacketNoLock(p);
/* Wakeup anyone waiting for packets */
rxi_PacketsUnWait();
MUTEX_EXIT(&rx_freePktQ_lock);
USERPRI;
}
-
+#endif /* RX_ENABLE_TSFPQ */
/* rxi_AllocPacket sets up p->length so it reflects the number of
* bytes in the packet at this point, **not including** the header.
* The header is absolutely necessary, besides, this is the way the
* length field is usually used */
+#ifdef RX_ENABLE_TSFPQ
struct rx_packet *
rxi_AllocPacketNoLock(int class)
{
register struct rx_packet *p;
+ register struct rx_ts_info_t * rx_ts_info;
+
+ RX_TS_INFO_GET(rx_ts_info);
#ifdef KERNEL
if (rxi_OverQuota(class)) {
rxi_NeedMorePackets = TRUE;
- MUTEX_ENTER(&rx_stats_mutex);
switch (class) {
case RX_PACKET_CLASS_RECEIVE:
- rx_stats.receivePktAllocFailures++;
+ rx_MutexIncrement(rx_stats.receivePktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_SEND:
- rx_stats.sendPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.sendPktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_SPECIAL:
- rx_stats.specialPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.specialPktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_RECV_CBUF:
- rx_stats.receiveCbufPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.receiveCbufPktAllocFailures, rx_stats_mutex);
break;
case RX_PACKET_CLASS_SEND_CBUF:
- rx_stats.sendCbufPktAllocFailures++;
+ rx_MutexIncrement(rx_stats.sendCbufPktAllocFailures, rx_stats_mutex);
+ break;
+ }
+ return (struct rx_packet *)0;
+ }
+#endif /* KERNEL */
+
+ rx_MutexIncrement(rx_stats.packetRequests, rx_stats_mutex);
+ if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
+
+#ifdef KERNEL
+ if (queue_IsEmpty(&rx_freePacketQueue))
+ osi_Panic("rxi_AllocPacket error");
+#else /* KERNEL */
+ if (queue_IsEmpty(&rx_freePacketQueue))
+ rxi_MorePacketsNoLock(rx_initSendWindow);
+#endif /* KERNEL */
+
+
+ RX_TS_FPQ_GTOL(rx_ts_info);
+ }
+
+ RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
+
+ dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
+
+
+ /* have to do this here because rx_FlushWrite fiddles with the iovs in
+ * order to truncate outbound packets. In the near future, may need
+ * to allocate bufs from a static pool here, and/or in AllocSendPacket
+ */
+ RX_PACKET_IOV_FULLINIT(p);
+ return p;
+}
+#else /* RX_ENABLE_TSFPQ */
+struct rx_packet *
+rxi_AllocPacketNoLock(int class)
+{
+ register struct rx_packet *p;
+
+#ifdef KERNEL
+ if (rxi_OverQuota(class)) {
+ rxi_NeedMorePackets = TRUE;
+ switch (class) {
+ case RX_PACKET_CLASS_RECEIVE:
+ rx_MutexIncrement(rx_stats.receivePktAllocFailures, rx_stats_mutex);
+ break;
+ case RX_PACKET_CLASS_SEND:
+ rx_MutexIncrement(rx_stats.sendPktAllocFailures, rx_stats_mutex);
+ break;
+ case RX_PACKET_CLASS_SPECIAL:
+ rx_MutexIncrement(rx_stats.specialPktAllocFailures, rx_stats_mutex);
+ break;
+ case RX_PACKET_CLASS_RECV_CBUF:
+ rx_MutexIncrement(rx_stats.receiveCbufPktAllocFailures, rx_stats_mutex);
+ break;
+ case RX_PACKET_CLASS_SEND_CBUF:
+ rx_MutexIncrement(rx_stats.sendCbufPktAllocFailures, rx_stats_mutex);
break;
}
- MUTEX_EXIT(&rx_stats_mutex);
return (struct rx_packet *)0;
}
#endif /* KERNEL */
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.packetRequests++;
- MUTEX_EXIT(&rx_stats_mutex);
+ rx_MutexIncrement(rx_stats.packetRequests, rx_stats_mutex);
#ifdef KERNEL
if (queue_IsEmpty(&rx_freePacketQueue))
rx_nFreePackets--;
p = queue_First(&rx_freePacketQueue, rx_packet);
- if (!(p->flags & RX_PKTFLAG_FREE))
- osi_Panic("rxi_AllocPacket: packet not free\n");
+ queue_Remove(p);
+ RX_FPQ_MARK_USED(p);
- dpf(("Alloc %x, class %d\n", (int)p, class));
+ dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
- queue_Remove(p);
- p->flags = 0; /* clear RX_PKTFLAG_FREE, initialize the rest */
- p->header.flags = 0;
/* have to do this here because rx_FlushWrite fiddles with the iovs in
* order to truncate outbound packets. In the near future, may need
* to allocate bufs from a static pool here, and/or in AllocSendPacket
*/
- p->wirevec[0].iov_base = (char *)(p->wirehead);
- p->wirevec[0].iov_len = RX_HEADER_SIZE;
- p->wirevec[1].iov_base = (char *)(p->localdata);
- p->wirevec[1].iov_len = RX_FIRSTBUFFERSIZE;
- p->niovecs = 2;
- p->length = RX_FIRSTBUFFERSIZE;
+ RX_PACKET_IOV_FULLINIT(p);
+ return p;
+}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+struct rx_packet *
+rxi_AllocPacketTSFPQ(int class, int pull_global)
+{
+ register struct rx_packet *p;
+ register struct rx_ts_info_t * rx_ts_info;
+
+ RX_TS_INFO_GET(rx_ts_info);
+
+ rx_MutexIncrement(rx_stats.packetRequests, rx_stats_mutex);
+ if (pull_global && queue_IsEmpty(&rx_ts_info->_FPQ)) {
+ MUTEX_ENTER(&rx_freePktQ_lock);
+
+ if (queue_IsEmpty(&rx_freePacketQueue))
+ rxi_MorePacketsNoLock(rx_initSendWindow);
+
+ RX_TS_FPQ_GTOL(rx_ts_info);
+
+ MUTEX_EXIT(&rx_freePktQ_lock);
+ } else if (queue_IsEmpty(&rx_ts_info->_FPQ)) {
+ return NULL;
+ }
+
+ RX_TS_FPQ_CHECKOUT(rx_ts_info,p);
+
+ dpf(("Alloc %lx, class %d\n", (unsigned long)p, class));
+
+ /* have to do this here because rx_FlushWrite fiddles with the iovs in
+ * order to truncate outbound packets. In the near future, may need
+ * to allocate bufs from a static pool here, and/or in AllocSendPacket
+ */
+ RX_PACKET_IOV_FULLINIT(p);
return p;
}
+#endif /* RX_ENABLE_TSFPQ */
+
+#ifdef RX_ENABLE_TSFPQ
+struct rx_packet *
+rxi_AllocPacket(int class)
+{
+ register struct rx_packet *p;
+ p = rxi_AllocPacketTSFPQ(class, RX_TS_FPQ_PULL_GLOBAL);
+ return p;
+}
+#else /* RX_ENABLE_TSFPQ */
struct rx_packet *
rxi_AllocPacket(int class)
{
MUTEX_EXIT(&rx_freePktQ_lock);
return p;
}
+#endif /* RX_ENABLE_TSFPQ */
/* This guy comes up with as many buffers as it {takes,can get} given
* the MTU for this call. It also sets the packet length before
rx_GetSecurityHeaderSize(rx_ConnectionOf(call)) +
rx_GetSecurityMaxTrailerSize(rx_ConnectionOf(call));
+#ifdef RX_ENABLE_TSFPQ
+ if ((p = rxi_AllocPacketTSFPQ(RX_PACKET_CLASS_SEND, 0))) {
+ want += delta;
+ want = MIN(want, mud);
+
+ if ((unsigned)want > p->length)
+ (void)rxi_AllocDataBuf(p, (want - p->length),
+ RX_PACKET_CLASS_SEND_CBUF);
+
+ if ((unsigned)p->length > mud)
+ p->length = mud;
+
+ if (delta >= p->length) {
+ rxi_FreePacket(p);
+ p = NULL;
+ } else {
+ p->length -= delta;
+ }
+ return p;
+ }
+#endif /* RX_ENABLE_TSFPQ */
+
while (!(call->error)) {
MUTEX_ENTER(&rx_freePktQ_lock);
/* if an error occurred, or we get the packet we want, we're done */
}
#ifndef KERNEL
-
+#ifdef AFS_NT40_ENV
+/* Windows does not use file descriptors. */
+#define CountFDs(amax) 0
+#else
/* count the number of used FDs */
static int
CountFDs(register int amax)
}
return count;
}
-
+#endif /* AFS_NT40_ENV */
#else /* KERNEL */
#define CountFDs(amax) amax
* the data length of the packet is stored in the packet structure.
* The header is decoded. */
int
-rxi_ReadPacket(int socket, register struct rx_packet *p, afs_uint32 * host,
+rxi_ReadPacket(osi_socket socket, register struct rx_packet *p, afs_uint32 * host,
u_short * port)
{
struct sockaddr_in from;
p->length = (nbytes - RX_HEADER_SIZE);
if ((nbytes > tlen) || (p->length & 0x8000)) { /* Bogus packet */
- if (nbytes > 0)
- rxi_MorePackets(rx_initSendWindow);
-#ifndef AFS_NT40_ENV
- else if (nbytes < 0 && errno == EWOULDBLOCK) {
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.noPacketOnRead++;
- MUTEX_EXIT(&rx_stats_mutex);
- }
-#endif
- else {
+ if (nbytes < 0 && errno == EWOULDBLOCK) {
+ rx_MutexIncrement(rx_stats.noPacketOnRead, rx_stats_mutex);
+ } else if (nbytes <= 0) {
MUTEX_ENTER(&rx_stats_mutex);
rx_stats.bogusPacketOnRead++;
rx_stats.bogusHost = from.sin_addr.s_addr;
MUTEX_EXIT(&rx_stats_mutex);
- dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr,
- from.sin_port, nbytes));
+ dpf(("B: bogus packet from [%x,%d] nb=%d", ntohl(from.sin_addr.s_addr),
+ ntohs(from.sin_port), nbytes));
}
return 0;
- } else {
+ }
+#ifdef RXDEBUG
+ else if ((rx_intentionallyDroppedOnReadPer100 > 0)
+ && (random() % 100 < rx_intentionallyDroppedOnReadPer100)) {
+ rxi_DecodePacketHeader(p);
+
+ *host = from.sin_addr.s_addr;
+ *port = from.sin_port;
+
+ dpf(("Dropped %d %s: %x.%u.%u.%u.%u.%u.%u flags %d len %d",
+ p->header.serial, rx_packetTypes[p->header.type - 1], ntohl(*host), ntohs(*port), p->header.serial,
+ p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags,
+ p->length));
+ rxi_TrimDataBufs(p, 1);
+ return 0;
+ }
+#endif
+ else {
/* Extract packet header. */
rxi_DecodePacketHeader(p);
*port = from.sin_port;
if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) {
struct rx_peer *peer;
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.packetsRead[p->header.type - 1]++;
- MUTEX_EXIT(&rx_stats_mutex);
+ rx_MutexIncrement(rx_stats.packetsRead[p->header.type - 1], rx_stats_mutex);
/*
* Try to look up this peer structure. If it doesn't exist,
* don't create a new one -
* never be cleaned up.
*/
peer = rxi_FindPeer(*host, *port, 0, 0);
- if (peer) {
+ /* Since this may not be associated with a connection,
+ * it may have no refCount, meaning we could race with
+ * ReapConnections
+ */
+ if (peer && (peer->refCount > 0)) {
MUTEX_ENTER(&peer->peer_lock);
hadd32(peer->bytesReceived, p->length);
MUTEX_EXIT(&peer->peer_lock);
int length, int istack)
{
struct msghdr msg;
+ int ret;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = dvec;
msg.msg_name = addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
- rxi_Sendmsg(socket, &msg, 0);
+ ret = rxi_Sendmsg(socket, &msg, 0);
- return 0;
+ return ret;
}
#elif !defined(UKERNEL)
/*
#define m_cpytoc(a, b, c, d) cpytoc(a, b, c, d)
#define m_cpytoiovec(a, b, c, d, e) cpytoiovec(a, b, c, d, e)
#else
-#if !defined(AFS_LINUX20_ENV)
+#if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
static int
m_cpytoiovec(struct mbuf *m, int off, int len, struct iovec iovs[], int niovs)
{
#endif /* LINUX */
#endif /* AFS_SUN5_ENV */
-#if !defined(AFS_LINUX20_ENV)
+#if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN80_ENV)
int
rx_mb_to_packet(amb, free, hdr_len, data_len, phandle)
#if defined(AFS_SUN5_ENV) || defined(AFS_HPUX110_ENV)
#ifndef RX_ENABLE_LOCKS
tstat.waitingForPackets = rx_waitingForPackets;
#endif
+ MUTEX_ENTER(&rx_serverPool_lock);
tstat.nFreePackets = htonl(rx_nFreePackets);
tstat.callsExecuted = htonl(rxi_nCalls);
tstat.packetReclaims = htonl(rx_packetReclaims);
tstat.usedFDs = CountFDs(64);
tstat.nWaiting = htonl(rx_nWaiting);
+ tstat.nWaited = htonl(rx_nWaited);
queue_Count(&rx_idleServerQueue, np, nqe, rx_serverQueueEntry,
tstat.idleThreads);
+ MUTEX_EXIT(&rx_serverPool_lock);
tstat.idleThreads = htonl(tstat.idleThreads);
tl = sizeof(struct rx_debugStats) - ap->length;
if (tl > 0)
} else
nbytes -= apacket->wirevec[i].iov_len;
}
- AFS_RXGUNLOCK();
#ifdef KERNEL
#ifdef RX_KERNEL_TRACE
if (ICL_SETACTIVE(afs_iclSetp)) {
AFS_GLOCK();
#endif
#endif
- AFS_RXGLOCK();
if (saven) { /* means we truncated the packet above. */
apacket->wirevec[i - 1].iov_len = savelen;
apacket->niovecs = saven;
* blocking socket, but unfortunately the interface doesn't
* allow us to have the socket block in send mode, and not
* block in receive mode */
- AFS_RXGUNLOCK();
#ifdef KERNEL
waslocked = ISAFS_GLOCK();
#ifdef RX_KERNEL_TRACE
osi_NetSend(socket, &addr, p->wirevec, p->niovecs,
p->length + RX_HEADER_SIZE, istack)) != 0) {
/* send failed, so let's hurry up the resend, eh? */
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.netSendFailures++;
- MUTEX_EXIT(&rx_stats_mutex);
+ rx_MutexIncrement(rx_stats.netSendFailures, rx_stats_mutex);
p->retryTime = p->timeSent; /* resend it very soon */
clock_Addmsec(&(p->retryTime),
10 + (((afs_uint32) p->backoff) << 8));
-
-#if defined(KERNEL) && defined(AFS_LINUX20_ENV)
- /* Linux is nice -- it can tell us right away that we cannot
- * reach this recipient by returning an ENETUNREACH error
- * code. So, when this happens let's "down" the host NOW so
+ /* Some systems are nice and tell us right away that we cannot
+ * reach this recipient by returning an error code.
+ * So, when this happens let's "down" the host NOW so
* we don't sit around waiting for this host to timeout later.
*/
- if (call && code == -ENETUNREACH)
- call->lastReceiveTime = 0;
+ if (call &&
+#ifdef AFS_NT40_ENV
+ code == -1 && WSAGetLastError() == WSAEHOSTUNREACH
+#elif defined(AFS_LINUX20_ENV) && defined(KERNEL)
+ code == -ENETUNREACH
+#elif defined(AFS_DARWIN_ENV) && defined(KERNEL)
+ code == EHOSTUNREACH
+#else
+ 0
#endif
+ )
+ call->lastReceiveTime = 0;
}
#ifdef KERNEL
#ifdef RX_KERNEL_TRACE
AFS_GLOCK();
#endif
#endif
- AFS_RXGLOCK();
#ifdef RXDEBUG
}
- dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %x resend %d.%0.3d len %d", deliveryType, p->header.serial, rx_packetTypes[p->header.type - 1], peer->host, peer->port, p->header.serial, p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags, (int)p, p->retryTime.sec, p->retryTime.usec / 1000, p->length));
+ dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %lx resend %d.%0.3d len %d", deliveryType, p->header.serial, rx_packetTypes[p->header.type - 1], ntohl(peer->host), ntohs(peer->port), p->header.serial, p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags, (unsigned long)p, p->retryTime.sec, p->retryTime.usec / 1000, p->length));
#endif
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.packetsSent[p->header.type - 1]++;
- MUTEX_EXIT(&rx_stats_mutex);
+ rx_MutexIncrement(rx_stats.packetsSent[p->header.type - 1], rx_stats_mutex);
MUTEX_ENTER(&peer->peer_lock);
hadd32(peer->bytesSent, p->length);
MUTEX_EXIT(&peer->peer_lock);
* blocking socket, but unfortunately the interface doesn't
* allow us to have the socket block in send mode, and not
* block in receive mode */
- AFS_RXGUNLOCK();
#if defined(AFS_SUN5_ENV) && defined(KERNEL)
waslocked = ISAFS_GLOCK();
if (!istack && waslocked)
osi_NetSend(socket, &addr, &wirevec[0], len + 1, length,
istack)) != 0) {
/* send failed, so let's hurry up the resend, eh? */
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.netSendFailures++;
- MUTEX_EXIT(&rx_stats_mutex);
+ rx_MutexIncrement(rx_stats.netSendFailures, rx_stats_mutex);
for (i = 0; i < len; i++) {
p = list[i];
p->retryTime = p->timeSent; /* resend it very soon */
clock_Addmsec(&(p->retryTime),
10 + (((afs_uint32) p->backoff) << 8));
}
-#if defined(KERNEL) && defined(AFS_LINUX20_ENV)
- /* Linux is nice -- it can tell us right away that we cannot
- * reach this recipient by returning an ENETUNREACH error
- * code. So, when this happens let's "down" the host NOW so
+ /* Some systems are nice and tell us right away that we cannot
+ * reach this recipient by returning an error code.
+ * So, when this happens let's "down" the host NOW so
* we don't sit around waiting for this host to timeout later.
*/
- if (call && code == -ENETUNREACH)
- call->lastReceiveTime = 0;
+ if (call &&
+#ifdef AFS_NT40_ENV
+ code == -1 && WSAGetLastError() == WSAEHOSTUNREACH
+#elif defined(AFS_LINUX20_ENV) && defined(KERNEL)
+ code == -ENETUNREACH
+#elif defined(AFS_DARWIN_ENV) && defined(KERNEL)
+ code == EHOSTUNREACH
+#else
+ 0
#endif
+ )
+ call->lastReceiveTime = 0;
}
#if defined(AFS_SUN5_ENV) && defined(KERNEL)
if (!istack && waslocked)
AFS_GLOCK();
#endif
- AFS_RXGLOCK();
#ifdef RXDEBUG
}
assert(p != NULL);
- dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %x resend %d.%0.3d len %d",
- deliveryType, p->header.serial, rx_packetTypes[p->header.type - 1],
- peer->host, peer->port, p->header.serial, p->header.epoch,
- p->header.cid, p->header.callNumber, p->header.seq, p->header.flags,
- (int)p, p->retryTime.sec, p->retryTime.usec / 1000, p->length));
+ dpf(("%c %d %s: %x.%u.%u.%u.%u.%u.%u flags %d, packet %lx resend %d.%0.3d len %d", deliveryType, p->header.serial, rx_packetTypes[p->header.type - 1], ntohl(peer->host), ntohs(peer->port), p->header.serial, p->header.epoch, p->header.cid, p->header.callNumber, p->header.seq, p->header.flags, (unsigned long)p, p->retryTime.sec, p->retryTime.usec / 1000, p->length));
#endif
- MUTEX_ENTER(&rx_stats_mutex);
- rx_stats.packetsSent[p->header.type - 1]++;
- MUTEX_EXIT(&rx_stats_mutex);
+ rx_MutexIncrement(rx_stats.packetsSent[p->header.type - 1], rx_stats_mutex);
MUTEX_ENTER(&peer->peer_lock);
-
hadd32(peer->bytesSent, p->length);
MUTEX_EXIT(&peer->peer_lock);
}
register struct rx_packet *p, register int last)
{
register struct rx_connection *conn = call->conn;
- int i, j;
+ int i;
ssize_t len; /* len must be a signed type; it can go negative */
p->flags &= ~RX_PKTFLAG_ACKED;
p->header.cid = (conn->cid | call->channel);
p->header.serviceId = conn->serviceId;
p->header.securityIndex = conn->securityIndex;
+
+ /* No data packets on call 0. Where do these come from? */
+ if (*call->callNumber == 0)
+ *call->callNumber = 1;
+
p->header.callNumber = *call->callNumber;
p->header.seq = call->tnext++;
p->header.epoch = conn->epoch;
}
if (len > 0) {
osi_Panic("PrepareSendPacket 1\n"); /* MTUXXX */
- } else {
+ } else if (i < p->niovecs) {
/* Free any extra elements in the wirevec */
- for (j = MAX(2, i); j < p->niovecs; j++) {
- rxi_freeCBuf(RX_CBUF_TO_PACKET(p->wirevec[j].iov_base, p));
- }
+#if defined(RX_ENABLE_TSFPQ)
+ rxi_FreeDataBufsTSFPQ(p, i, 1 /* allow global pool flush if overquota */);
+#else /* !RX_ENABLE_TSFPQ */
+ MUTEX_ENTER(&rx_freePktQ_lock);
+ rxi_FreeDataBufsNoLock(p, i);
+ MUTEX_EXIT(&rx_freePktQ_lock);
+#endif /* !RX_ENABLE_TSFPQ */
+
p->niovecs = i;
- p->wirevec[i - 1].iov_len += len;
}
+ p->wirevec[i - 1].iov_len += len;
RXS_PreparePacket(conn->securityObject, call, p);
}