Index: openafs/src/afs/afs_daemons.c
diff -c openafs/src/afs/afs_daemons.c:1.43.2.2 openafs/src/afs/afs_daemons.c:1.43.2.2.2.2
*** openafs/src/afs/afs_daemons.c:1.43.2.2	Thu Nov  8 09:40:12 2007
--- openafs/src/afs/afs_daemons.c	Tue May 20 18:17:32 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_daemons.c,v 1.43.2.2 2007/11/08 14:40:12 shadow Exp $");
  
  #ifdef AFS_AIX51_ENV
  #define __FULL_PROTO
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_daemons.c,v 1.43.2.2.2.2 2008/05/20 22:17:32 shadow Exp $");
  
  #ifdef AFS_AIX51_ENV
  #define __FULL_PROTO
***************
*** 52,57 ****
--- 52,58 ----
  afs_int32 afs_probe_interval = DEFAULT_PROBE_INTERVAL;
  afs_int32 afs_probe_all_interval = 600;
  afs_int32 afs_nat_probe_interval = 60;
+ afs_int32 afs_preCache = 0;
  
  #define PROBE_WAIT() (1000 * (afs_probe_interval - ((afs_random() & 0x7fffffff) \
  		      % (afs_probe_interval/2))))
***************
*** 478,494 ****
  {
      register struct dcache *tdc;
      register struct vcache *tvc;
!     afs_size_t offset, len;
      struct vrequest treq;
  
      AFS_STATCNT(BPrefetch);
      if ((len = afs_InitReq(&treq, ab->cred)))
  	return;
      tvc = ab->vc;
!     tdc = afs_GetDCache(tvc, ab->size_parm[0], &treq, &offset, &len, 1);
!     if (tdc) {
! 	afs_PutDCache(tdc);
!     }
      /* now, dude may be waiting for us to clear DFFetchReq bit; do so.  Can't
       * use tdc from GetDCache since afs_GetDCache may fail, but someone may
       * be waiting for our wakeup anyway.
--- 479,500 ----
  {
      register struct dcache *tdc;
      register struct vcache *tvc;
!     afs_size_t offset, len, abyte, totallen = 0;
      struct vrequest treq;
  
      AFS_STATCNT(BPrefetch);
      if ((len = afs_InitReq(&treq, ab->cred)))
  	return;
+     abyte = ab->size_parm[0];
      tvc = ab->vc;
!     do {
! 	tdc = afs_GetDCache(tvc, abyte, &treq, &offset, &len, 1);
! 	if (tdc) {
! 	    afs_PutDCache(tdc);
! 	}
! 	abyte+=len; 
! 	totallen += len;
!     } while ((totallen < afs_preCache) && tdc && (len > 0));
      /* now, dude may be waiting for us to clear DFFetchReq bit; do so.  Can't
       * use tdc from GetDCache since afs_GetDCache may fail, but someone may
       * be waiting for our wakeup anyway.
Index: openafs/src/afs/afs_icl.c
diff -c openafs/src/afs/afs_icl.c:1.1.2.3 openafs/src/afs/afs_icl.c:1.1.2.3.4.1
*** openafs/src/afs/afs_icl.c:1.1.2.3	Wed Aug  2 15:01:22 2006
--- openafs/src/afs/afs_icl.c	Tue May 20 15:52:29 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_icl.c,v 1.1.2.3 2006/08/02 19:01:22 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_icl.c,v 1.1.2.3.4.1 2008/05/20 19:52:29 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 1016,1025 ****
      ObtainWriteLock(&logp->lock, 189);
      if (--logp->setCount == 0) {
  	/* no more users -- free it (but keep log structure around) */
  #ifdef	KERNEL_HAVE_PIN
  	unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
  #endif
- 	afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
  	logp->firstUsed = logp->firstFree = 0;
  	logp->logElements = 0;
  	logp->datap = NULL;
--- 1016,1025 ----
      ObtainWriteLock(&logp->lock, 189);
      if (--logp->setCount == 0) {
  	/* no more users -- free it (but keep log structure around) */
+ 	afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
  #ifdef	KERNEL_HAVE_PIN
  	unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
  #endif
  	logp->firstUsed = logp->firstFree = 0;
  	logp->logElements = 0;
  	logp->datap = NULL;
***************
*** 1042,1051 ****
  	logp->logElements = 0;
  
  	/* free and allocate a new one */
  #ifdef	KERNEL_HAVE_PIN
  	unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
  #endif
- 	afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
  	logp->datap =
  	    (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * logSize);
  #ifdef	KERNEL_HAVE_PIN
--- 1042,1051 ----
  	logp->logElements = 0;
  
  	/* free and allocate a new one */
+ 	afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
  #ifdef	KERNEL_HAVE_PIN
  	unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
  #endif
  	logp->datap =
  	    (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * logSize);
  #ifdef	KERNEL_HAVE_PIN
***************
*** 1069,1078 ****
  	    /* found the dude we want to remove */
  	    *lpp = logp->nextp;
  	    osi_FreeSmallSpace(logp->name);
  #ifdef KERNEL_HAVE_PIN
  	    unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
  #endif
- 	    afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
  	    osi_FreeSmallSpace(logp);
  	    break;		/* won't find it twice */
  	}
--- 1069,1078 ----
  	    /* found the dude we want to remove */
  	    *lpp = logp->nextp;
  	    osi_FreeSmallSpace(logp->name);
+ 	    afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
  #ifdef KERNEL_HAVE_PIN
  	    unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
  #endif
  	    osi_FreeSmallSpace(logp);
  	    break;		/* won't find it twice */
  	}
***************
*** 1330,1339 ****
  	    /* found the dude we want to remove */
  	    *lpp = setp->nextp;
  	    osi_FreeSmallSpace(setp->name);
  #ifdef	KERNEL_HAVE_PIN
  	    unpin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
  #endif
- 	    afs_osi_Free(setp->eventFlags, ICL_DEFAULTEVENTS);
  	    for (i = 0; i < ICL_LOGSPERSET; i++) {
  		if ((tlp = setp->logs[i]))
  		    afs_icl_LogReleNL(tlp);
--- 1330,1339 ----
  	    /* found the dude we want to remove */
  	    *lpp = setp->nextp;
  	    osi_FreeSmallSpace(setp->name);
+ 	    afs_osi_Free(setp->eventFlags, ICL_DEFAULTEVENTS);
  #ifdef	KERNEL_HAVE_PIN
  	    unpin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
  #endif
  	    for (i = 0; i < ICL_LOGSPERSET; i++) {
  		if ((tlp = setp->logs[i]))
  		    afs_icl_LogReleNL(tlp);
Index: openafs/src/afs/afs_osi_alloc.c
diff -c openafs/src/afs/afs_osi_alloc.c:1.11.6.5 openafs/src/afs/afs_osi_alloc.c:1.11.6.5.2.1
*** openafs/src/afs/afs_osi_alloc.c:1.11.6.5	Thu Dec 13 14:18:29 2007
--- openafs/src/afs/afs_osi_alloc.c	Tue May 20 15:52:29 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_alloc.c,v 1.11.6.5 2007/12/13 19:18:29 shadow Exp $");
  
  
  
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_osi_alloc.c,v 1.11.6.5.2.1 2008/05/20 19:52:29 shadow Exp $");
  
  
  
***************
*** 233,250 ****
  
  	while ((tp = freePacketList)) {
  	    freePacketList = tp->next;
  #ifdef  KERNEL_HAVE_PIN
  	    unpin(tp, AFS_LRALLOCSIZ);
  #endif
- 	    afs_osi_Free(tp, AFS_LRALLOCSIZ);
  	}
  
  	while ((tp = freeSmallList)) {
  	    freeSmallList = tp->next;
  #ifdef  KERNEL_HAVE_PIN
  	    unpin(tp, AFS_SMALLOCSIZ);
  #endif
- 	    afs_osi_Free(tp, AFS_SMALLOCSIZ);
  	}
  	LOCK_INIT(&osi_fsplock, "osi_fsplock");
  	LOCK_INIT(&osi_flplock, "osi_flplock");
--- 233,250 ----
  
  	while ((tp = freePacketList)) {
  	    freePacketList = tp->next;
+ 	    afs_osi_Free(tp, AFS_LRALLOCSIZ);
  #ifdef  KERNEL_HAVE_PIN
  	    unpin(tp, AFS_LRALLOCSIZ);
  #endif
  	}
  
  	while ((tp = freeSmallList)) {
  	    freeSmallList = tp->next;
+ 	    afs_osi_Free(tp, AFS_SMALLOCSIZ);
  #ifdef  KERNEL_HAVE_PIN
  	    unpin(tp, AFS_SMALLOCSIZ);
  #endif
  	}
  	LOCK_INIT(&osi_fsplock, "osi_fsplock");
  	LOCK_INIT(&osi_flplock, "osi_flplock");
Index: openafs/src/afs/afs_pioctl.c
diff -c openafs/src/afs/afs_pioctl.c:1.110.2.15 openafs/src/afs/afs_pioctl.c:1.110.2.15.2.2
*** openafs/src/afs/afs_pioctl.c:1.110.2.15	Sat Mar 22 00:19:13 2008
--- openafs/src/afs/afs_pioctl.c	Wed May 21 00:22:43 2008
***************
*** 11,17 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_pioctl.c,v 1.110.2.15 2008/03/22 04:19:13 jaltman Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #ifdef AFS_OBSD_ENV
--- 11,17 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_pioctl.c,v 1.110.2.15.2.2 2008/05/21 04:22:43 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #ifdef AFS_OBSD_ENV
***************
*** 92,97 ****
--- 92,98 ----
  DECL_PIOCTL(PCallBackAddr);
  DECL_PIOCTL(PNFSNukeCreds);
  DECL_PIOCTL(PNewUuid);
+ DECL_PIOCTL(PPrecache); 
  
  /*
   * A macro that says whether we're going to need HandleClientContext().
***************
*** 200,205 ****
--- 201,209 ----
      PBogus,			/* 7 */
      PBogus,			/* 8 */
      PNewUuid,                   /* 9 */ 
+     PBogus,                     /* 0 */
+     PBogus,                     /* 0 */
+     PPrecache,                  /* 12 */
  };
  
  static int (*(OpioctlSw[])) () = {
***************
*** 2063,2068 ****
--- 2067,2084 ----
  	return EACCES;
  }
  
+ DECL_PIOCTL(PPrecache)
+ {
+     afs_int32 newValue;
+ 
+     /*AFS_STATCNT(PPrecache);*/
+     if (!afs_osi_suser(*acred))
+ 	return EACCES;
+     memcpy((char *)&newValue, ain, sizeof(afs_int32));
+     afs_preCache = newValue*1024;
+     return 0;
+ }
+ 
  DECL_PIOCTL(PSetCacheSize)
  {
      afs_int32 newValue;
Index: openafs/src/afs/afs_prototypes.h
diff -c openafs/src/afs/afs_prototypes.h:1.74.2.14 openafs/src/afs/afs_prototypes.h:1.74.2.14.2.1
*** openafs/src/afs/afs_prototypes.h:1.74.2.14	Wed Apr 30 15:08:04 2008
--- openafs/src/afs/afs_prototypes.h	Tue May 20 17:59:38 2008
***************
*** 199,204 ****
--- 199,205 ----
  extern afs_int32 afs_gcpags_procsize;
  extern afs_int32 afs_CheckServerDaemonStarted;
  extern afs_int32 afs_probe_interval;
+ extern afs_int32 afs_preCache;
  
  extern void afs_Daemon(void);
  extern struct brequest *afs_BQueue(register short aopcode,
Index: openafs/src/afs/afs_vcache.c
diff -c openafs/src/afs/afs_vcache.c:1.114.2.7 openafs/src/afs/afs_vcache.c:1.114.2.7.2.1
*** openafs/src/afs/afs_vcache.c:1.114.2.7	Thu Dec 13 14:47:46 2007
--- openafs/src/afs/afs_vcache.c	Tue May 20 15:52:29 2008
***************
*** 39,45 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_vcache.c,v 1.114.2.7 2007/12/13 19:47:46 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
--- 39,45 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/afs_vcache.c,v 1.114.2.7.2.1 2008/05/20 19:52:29 shadow Exp $");
  
  #include "afs/sysincludes.h"	/*Standard vendor system headers */
  #include "afsincludes.h"	/*AFS-based standard headers */
***************
*** 3087,3098 ****
      }
      afs_cbrSpace = 0;
  
- #ifdef  KERNEL_HAVE_PIN
-     unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
- #endif
  #if !defined(AFS_OSF_ENV) && !defined(AFS_LINUX22_ENV)
      afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
  #endif
  
  #if !defined(AFS_OSF_ENV) && !defined(AFS_LINUX22_ENV)
      freeVCList = Initial_freeVCList = 0;
--- 3087,3098 ----
      }
      afs_cbrSpace = 0;
  
  #if !defined(AFS_OSF_ENV) && !defined(AFS_LINUX22_ENV)
      afs_osi_Free(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
  #endif
+ #ifdef  KERNEL_HAVE_PIN
+     unpin(Initial_freeVCList, afs_cacheStats * sizeof(struct vcache));
+ #endif
  
  #if !defined(AFS_OSF_ENV) && !defined(AFS_LINUX22_ENV)
      freeVCList = Initial_freeVCList = 0;
Index: openafs/src/afs/LINUX/osi_vnodeops.c
diff -c openafs/src/afs/LINUX/osi_vnodeops.c:1.126.2.25 openafs/src/afs/LINUX/osi_vnodeops.c:1.126.2.25.2.2
*** openafs/src/afs/LINUX/osi_vnodeops.c:1.126.2.25	Tue Apr 15 08:29:37 2008
--- openafs/src/afs/LINUX/osi_vnodeops.c	Tue May 20 17:03:36 2008
***************
*** 22,28 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v 1.126.2.25 2008/04/15 12:29:37 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
--- 22,28 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/LINUX/osi_vnodeops.c,v 1.126.2.25.2.2 2008/05/20 21:03:36 shadow Exp $");
  
  #include "afs/sysincludes.h"
  #include "afsincludes.h"
***************
*** 1033,1039 ****
  	ip = AFSTOV(vcp);
  	afs_getattr(vcp, &vattr, credp);
  	afs_fill_inode(ip, &vattr);
! 	if (hlist_unhashed(&ip->i_hash))
  	    insert_inode_hash(ip);
      }
      dp->d_op = &afs_dentry_operations;
--- 1033,1047 ----
  	ip = AFSTOV(vcp);
  	afs_getattr(vcp, &vattr, credp);
  	afs_fill_inode(ip, &vattr);
! 	if (
! #ifdef HAVE_KERNEL_HLIST_UNHASHED
! 	    hlist_unhashed(&ip->i_hash)
! #elif defined(AFS_LINUX26_ENV)
! 	    ip->i_hash.pprev == NULL
! #else
! 	    ip->i_hash.prev == NULL
! #endif
! 	    )
  	    insert_inode_hash(ip);
      }
      dp->d_op = &afs_dentry_operations;
Index: openafs/src/afs/VNOPS/afs_vnop_open.c
diff -c openafs/src/afs/VNOPS/afs_vnop_open.c:1.11 openafs/src/afs/VNOPS/afs_vnop_open.c:1.11.20.1
*** openafs/src/afs/VNOPS/afs_vnop_open.c:1.11	Sun Apr  3 14:09:14 2005
--- openafs/src/afs/VNOPS/afs_vnop_open.c	Tue May 20 17:59:40 2008
***************
*** 18,24 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_open.c,v 1.11 2005/04/03 18:09:14 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 18,24 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_open.c,v 1.11.20.1 2008/05/20 21:59:40 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 150,155 ****
--- 150,184 ----
      }
  #endif
      ReleaseReadLock(&tvc->lock);
+     if ((afs_preCache != 0) && (writing == 0) && (vType(tvc) != VDIR) && 
+ 	(!afs_BBusy())) {
+ 	register struct dcache *tdc;
+ 	afs_size_t offset, len, totallen = 0;
+ 
+ 	tdc = afs_GetDCache(tvc, 0, &treq, &offset, &len, 1);
+ 
+ 	ObtainSharedLock(&tdc->mflock, 865);
+ 	if (!(tdc->mflags & DFFetchReq)) {
+ 	    struct brequest *bp;
+ 
+ 	    /* start the daemon (may already be running, however) */
+ 	    UpgradeSToWLock(&tdc->mflock, 666);
+ 	    tdc->mflags |= DFFetchReq;  /* guaranteed to be cleared by BKG or 
+ 					   GetDCache */
+ 	    /* last parm (1) tells bkg daemon to do an afs_PutDCache when it 
+ 	       is done, since we don't want to wait for it to finish before 
+ 	       doing so ourselves.
+ 	    */
+ 	    bp = afs_BQueue(BOP_FETCH, tvc, B_DONTWAIT, 0, acred,
+ 			    (afs_size_t) 0, (afs_size_t) 1, tdc);
+ 	    if (!bp) {
+ 		tdc->mflags &= ~DFFetchReq;
+ 	    }
+ 	    ReleaseWriteLock(&tdc->mflock);
+ 	} else {
+ 	    ReleaseSharedLock(&tdc->mflock);
+ 	}
+     }	
    done:
      afs_PutFakeStat(&fakestate);
      code = afs_CheckCode(code, &treq, 4);	/* avoid AIX -O bug */
Index: openafs/src/afs/VNOPS/afs_vnop_read.c
diff -c openafs/src/afs/VNOPS/afs_vnop_read.c:1.34.2.2 openafs/src/afs/VNOPS/afs_vnop_read.c:1.34.2.2.2.1
*** openafs/src/afs/VNOPS/afs_vnop_read.c:1.34.2.2	Sat Apr 26 23:54:14 2008
--- openafs/src/afs/VNOPS/afs_vnop_read.c	Tue May 20 17:59:40 2008
***************
*** 19,25 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_read.c,v 1.34.2.2 2008/04/27 03:54:14 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
--- 19,25 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/afs/VNOPS/afs_vnop_read.c,v 1.34.2.2.2.1 2008/05/20 21:59:40 shadow Exp $");
  
  #include "afs/sysincludes.h"	/* Standard vendor system headers */
  #include "afsincludes.h"	/* Afs-based standard headers */
***************
*** 388,399 ****
       */
      if (tdc) {
  	ReleaseReadLock(&tdc->lock);
- #if !defined(AFS_VM_RDWR_ENV)
  	/* try to queue prefetch, if needed */
! 	if (!noLock) {
  	    afs_PrefetchChunk(avc, tdc, acred, &treq);
  	}
- #endif
  	afs_PutDCache(tdc);
      }
      if (!noLock)
--- 388,403 ----
       */
      if (tdc) {
  	ReleaseReadLock(&tdc->lock);
  	/* try to queue prefetch, if needed */
! 	if (!noLock &&
! #ifndef AFS_VM_RDWR_ENV
! 	    afs_preCache
! #else
! 	    1
! #endif
! 	    ) {
  	    afs_PrefetchChunk(avc, tdc, acred, &treq);
  	}
  	afs_PutDCache(tdc);
      }
      if (!noLock)
Index: openafs/src/afsd/afs.rc.darwin
diff -c openafs/src/afsd/afs.rc.darwin:1.8.2.1 openafs/src/afsd/afs.rc.darwin:1.8.2.1.2.1
*** openafs/src/afsd/afs.rc.darwin:1.8.2.1	Mon Jan 21 15:57:23 2008
--- openafs/src/afsd/afs.rc.darwin	Wed May 21 09:50:34 2008
***************
*** 140,145 ****
--- 140,149 ----
  	fs sysname $AFS_SYSNAME
      fi
  
+     if [ -n "$AFS_PRECACHE" ] ; then
+ 	fs precache $AFS_PRECACHE
+     fi
+ 
  #
  # Run package to update the disk
  #
Index: openafs/src/cf/linux-test4.m4
diff -c openafs/src/cf/linux-test4.m4:1.29.2.41 openafs/src/cf/linux-test4.m4:1.29.2.41.2.1
*** openafs/src/cf/linux-test4.m4:1.29.2.41	Sat Apr 19 17:55:47 2008
--- openafs/src/cf/linux-test4.m4	Tue May 20 16:39:38 2008
***************
*** 511,516 ****
--- 511,528 ----
      CPPFLAGS="$save_CPPFLAGS"])
    AC_MSG_RESULT($ac_cv_linux_kernel_page_follow_link)])
  
+ AC_DEFUN([LINUX_KERNEL_HLIST_UNHASHED], [
+   AC_MSG_CHECKING([for hlist_unhashed])
+   AC_CACHE_VAL([ac_cv_linux_kernel_hlist_unhashed], [
+     save_CPPFLAGS="$CPPFLAGS"
+     CPPFLAGS="$CPPFLAGS -Werror-implicit-function-declaration"
+     AC_TRY_KBUILD(
+ [#include <linux/list.h>],
+ [hlist_unhashed(0);],
+       ac_cv_linux_kernel_hlist_unhashed=yes,
+       ac_cv_linux_kernel_hlist_unhashed=no)
+     CPPFLAGS="$save_CPPFLAGS"])
+   AC_MSG_RESULT($ac_cv_linux_kernel_hlist_unhashed)])
  
  AC_DEFUN([LINUX_FS_STRUCT_ADDRESS_SPACE_HAS_GFP_MASK], [
    AC_MSG_CHECKING([for gfp_mask in struct address_space])
Index: openafs/src/config/NTMakefile.amd64_w2k
diff -c openafs/src/config/NTMakefile.amd64_w2k:1.24.2.41 openafs/src/config/NTMakefile.amd64_w2k:1.24.2.41.2.1
*** openafs/src/config/NTMakefile.amd64_w2k:1.24.2.41	Mon Apr 21 11:27:55 2008
--- openafs/src/config/NTMakefile.amd64_w2k	Wed May 21 09:39:28 2008
***************
*** 84,90 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3500
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
--- 84,90 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3700
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
Index: openafs/src/config/NTMakefile.i386_nt40
diff -c openafs/src/config/NTMakefile.i386_nt40:1.84.2.40 openafs/src/config/NTMakefile.i386_nt40:1.84.2.40.2.1
*** openafs/src/config/NTMakefile.i386_nt40:1.84.2.40	Mon Apr 21 11:27:55 2008
--- openafs/src/config/NTMakefile.i386_nt40	Wed May 21 09:39:28 2008
***************
*** 84,90 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3500
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
--- 84,90 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3700
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
Index: openafs/src/config/NTMakefile.i386_w2k
diff -c openafs/src/config/NTMakefile.i386_w2k:1.23.2.41 openafs/src/config/NTMakefile.i386_w2k:1.23.2.41.2.1
*** openafs/src/config/NTMakefile.i386_w2k:1.23.2.41	Mon Apr 21 11:27:55 2008
--- openafs/src/config/NTMakefile.i386_w2k	Wed May 21 09:39:28 2008
***************
*** 84,90 ****
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3500
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
--- 84,90 ----
  #define used in WinNT/2000 installation and program version display
  AFSPRODUCT_VER_MAJOR=1
  AFSPRODUCT_VER_MINOR=5
! AFSPRODUCT_VER_PATCH=3700
  AFSPRODUCT_VER_BUILD=0
  
  AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
Index: openafs/src/config/venus.h
diff -c openafs/src/config/venus.h:1.12.2.4 openafs/src/config/venus.h:1.12.2.4.2.1
*** openafs/src/config/venus.h:1.12.2.4	Tue Jun 12 15:14:11 2007
--- openafs/src/config/venus.h	Tue May 20 17:59:41 2008
***************
*** 183,188 ****
--- 183,189 ----
  #define VIOC_CBADDR		_CVICEIOCTL(3)	/* push callback addr */
  #define VIOC_DISCON		_CVICEIOCTL(5)	/* set/get discon mode */
  #define VIOC_NEWUUID            _CVICEIOCTL(9)  /* new uuid */
+ #define VIOCPRECACHE            _CVICEIOCTL(12)  /* precache size */
  
  /* OpenAFS-specific 'O' pioctl's */
  #define VIOC_NFS_NUKE_CREDS	_OVICEIOCTL(1)	/* nuke creds for all PAG's */
Index: openafs/src/packaging/MacOS/OpenAFS.Info.plist.in
diff -c openafs/src/packaging/MacOS/OpenAFS.Info.plist.in:1.1.2.3 openafs/src/packaging/MacOS/OpenAFS.Info.plist.in:1.1.2.3.2.1
*** openafs/src/packaging/MacOS/OpenAFS.Info.plist.in:1.1.2.3	Wed Oct 24 23:43:39 2007
--- openafs/src/packaging/MacOS/OpenAFS.Info.plist.in	Wed May 21 09:50:32 2008
***************
*** 31,37 ****
  	<key>IFPkgFlagRelocatable</key>
  	<false/>
  	<key>IFPkgFlagRestartAction</key>
! 	<string>RecommendedRestart</string>
  	<key>IFPkgFlagRootVolumeOnly</key>
  	<true/>
  	<key>IFPkgFlagUpdateInstalledLanguages</key>
--- 31,37 ----
  	<key>IFPkgFlagRelocatable</key>
  	<false/>
  	<key>IFPkgFlagRestartAction</key>
! 	<string>NoRestart</string>
  	<key>IFPkgFlagRootVolumeOnly</key>
  	<true/>
  	<key>IFPkgFlagUpdateInstalledLanguages</key>
Index: openafs/src/packaging/MacOS/OpenAFS.info.in
diff -c openafs/src/packaging/MacOS/OpenAFS.info.in:1.1.2.3 openafs/src/packaging/MacOS/OpenAFS.info.in:1.1.2.3.2.1
*** openafs/src/packaging/MacOS/OpenAFS.info.in:1.1.2.3	Wed Oct 24 23:43:39 2007
--- openafs/src/packaging/MacOS/OpenAFS.info.in	Wed May 21 09:50:32 2008
***************
*** 11,16 ****
  Relocatable NO
  Required NO
  InstallOnly NO
! RequiresReboot YES
  InstallFat NO
  rootVolumeOnly YES
--- 11,16 ----
  Relocatable NO
  Required NO
  InstallOnly NO
! RequiresReboot NO
  InstallFat NO
  rootVolumeOnly YES
Index: openafs/src/packaging/MacOS/OpenAFS.post_install
diff -c openafs/src/packaging/MacOS/OpenAFS.post_install:1.7.2.4 openafs/src/packaging/MacOS/OpenAFS.post_install:1.7.2.4.2.1
*** openafs/src/packaging/MacOS/OpenAFS.post_install:1.7.2.4	Mon Jan 21 15:57:24 2008
--- openafs/src/packaging/MacOS/OpenAFS.post_install	Wed May 21 09:50:32 2008
***************
*** 108,110 ****
--- 108,114 ----
    # turn off execution of afssettings
    chmod a-x config/afssettings
  fi
+ 
+ #here we should run tools which configure the client, and then if it's enabled:
+ /Library/StartupItems/OpenAFS/OpenAFS start
+ 
Index: openafs/src/packaging/MacOS/OpenAFS.pre_upgrade
diff -c openafs/src/packaging/MacOS/OpenAFS.pre_upgrade:1.2.2.2 openafs/src/packaging/MacOS/OpenAFS.pre_upgrade:1.2.2.2.2.1
*** openafs/src/packaging/MacOS/OpenAFS.pre_upgrade:1.2.2.2	Wed Oct 24 23:43:39 2007
--- openafs/src/packaging/MacOS/OpenAFS.pre_upgrade	Wed May 21 09:50:32 2008
***************
*** 23,25 ****
--- 23,28 ----
    fi
  fi
  
+ if [ -f /Library/StartupItems/OpenAFS/OpenAFS ]; then
+   /Library/StartupItems/OpenAFS/OpenAFS stop
+ fi
Index: openafs/src/packaging/MacOS/afs.conf
diff -c openafs/src/packaging/MacOS/afs.conf:1.1.2.2 openafs/src/packaging/MacOS/afs.conf:1.1.2.2.2.1
*** openafs/src/packaging/MacOS/afs.conf:1.1.2.2	Mon Jan 21 15:57:24 2008
--- openafs/src/packaging/MacOS/afs.conf	Wed May 21 09:50:32 2008
***************
*** 54,60 ****
  #
  # You can override that default behavior by setting OPTIONS to a specific set
  # of flags.
! OPTIONS="-afsdb -stat 2000 -dcache 800 -daemons 3 -volumes 70 -dynroot -fakestat-all"
  
  # The default value for the client sysname (as returned by fs sysname) is
  # determined during the kernel module build and is taken from the architecture
--- 54,60 ----
  #
  # You can override that default behavior by setting OPTIONS to a specific set
  # of flags.
! OPTIONS="-chunksize 18 -afsdb -stat 5000 -dcache 800 -daemons 8 -volumes 70 -dynroot -fakestat-all"
  
  # The default value for the client sysname (as returned by fs sysname) is
  # determined during the kernel module build and is taken from the architecture
***************
*** 77,82 ****
--- 77,85 ----
  #    fs setserverprefs <host> <rank>
  #}
  
+ # Amount to read ahead, or comment out to disable
+ AFS_PRECACHE=5000
+ 
  # If you want to always run some command after starting OpenAFS, you can put
  # it here.  Note that you cannot run multiple commands, even combined with &&
  # or ; or similar shell meta-characters.  If you want to run multiple
Index: openafs/src/packaging/MacOS/buildpkg.sh.in
diff -c openafs/src/packaging/MacOS/buildpkg.sh.in:1.1.2.4 openafs/src/packaging/MacOS/buildpkg.sh.in:1.1.2.4.2.1
*** openafs/src/packaging/MacOS/buildpkg.sh.in:1.1.2.4	Mon Jan 21 15:57:24 2008
--- openafs/src/packaging/MacOS/buildpkg.sh.in	Wed May 21 09:50:32 2008
***************
*** 125,131 ****
      cp $CURDIR/CellServDB $PKGROOT/private/var/db/openafs/etc/CellServDB.master
      echo grand.central.org > $PKGROOT/private/var/db/openafs/etc/ThisCell.sample
      if [ $majorvers -ge 7 ]; then
! 	echo /afs:/var/db/openafs/cache:30000 > $PKGROOT/private/var/db/openafs/etc/cacheinfo.sample
          cp -RP $PKGROOT/Library/OpenAFS/Tools/etc/afssettings $PKGROOT/private/var/db/openafs/etc/config
  	cp settings.plist $PKGROOT/private/var/db/openafs/etc/config/settings.plist.orig
      else
--- 125,131 ----
      cp $CURDIR/CellServDB $PKGROOT/private/var/db/openafs/etc/CellServDB.master
      echo grand.central.org > $PKGROOT/private/var/db/openafs/etc/ThisCell.sample
      if [ $majorvers -ge 7 ]; then
! 	echo /afs:/var/db/openafs/cache:100000 > $PKGROOT/private/var/db/openafs/etc/cacheinfo.sample
          cp -RP $PKGROOT/Library/OpenAFS/Tools/etc/afssettings $PKGROOT/private/var/db/openafs/etc/config
  	cp settings.plist $PKGROOT/private/var/db/openafs/etc/config/settings.plist.orig
      else
***************
*** 210,223 ****
      cp CellServDB.list $PKGRES
      chown -R root${SEP}wheel $PKGRES
      rm -rf $CURDIR/OpenAFS.pkg
- 
-     # once we have cm cleanup in 10.4 this can go
-     if [ $majorvers -le 8 ]; then
- 	cat $RESSRC/OpenAFS.info|sed 's/RequiresReboot NO/RequiresReboot YES/'>$RESSRC/OpenAFS.info.new
- 	rm -f $RESSRC/OpenAFS.info
- 	mv $RESSRC/OpenAFS.info.new $RESSRC/OpenAFS.info
-     fi
- 
      if [ $majorvers -ge 7 ]; then
  	echo $package -build -p $CURDIR/OpenAFS.pkg -f $PKGROOT -r $PKGRES \
  	    -i OpenAFS.Info.plist -d OpenAFS.Description.plist
--- 210,215 ----
Index: openafs/src/rx/rx.c
diff -c openafs/src/rx/rx.c:1.97.2.20 openafs/src/rx/rx.c:1.97.2.20.2.3
*** openafs/src/rx/rx.c:1.97.2.20	Thu May  8 17:25:58 2008
--- openafs/src/rx/rx.c	Tue May 20 17:59:42 2008
***************
*** 17,23 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx.c,v 1.97.2.20 2008/05/08 21:25:58 shadow Exp $");
  
  #ifdef KERNEL
  #include "afs/sysincludes.h"
--- 17,23 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx.c,v 1.97.2.20.2.3 2008/05/20 21:59:42 shadow Exp $");
  
  #ifdef KERNEL
  #include "afs/sysincludes.h"
***************
*** 33,38 ****
--- 33,43 ----
  #include "h/socket.h"
  #endif
  #include "netinet/in.h"
+ #ifdef AFS_SUN57_ENV
+ #include "inet/common.h"
+ #include "inet/ip.h"
+ #include "inet/ip_ire.h"
+ #endif
  #include "afs/afs_args.h"
  #include "afs/afs_osi.h"
  #ifdef RX_KERNEL_TRACE
***************
*** 742,795 ****
  		 int serviceSecurityIndex)
  {
      int hashindex, i;
!     afs_int32 cid;
!     register struct rx_connection *conn;
  
      SPLVAR;
  
      clock_NewTime();
      dpf(("rx_NewConnection(host %x, port %u, service %u, securityObject %x, serviceSecurityIndex %d)\n", ntohl(shost), ntohs(sport), sservice, securityObject, serviceSecurityIndex));
  
      /* Vasilsi said: "NETPRI protects Cid and Alloc", but can this be true in
       * the case of kmem_alloc? */
!     conn = rxi_AllocConnection();
! #ifdef	RX_ENABLE_LOCKS
!     MUTEX_INIT(&conn->conn_call_lock, "conn call lock", MUTEX_DEFAULT, 0);
!     MUTEX_INIT(&conn->conn_data_lock, "conn call lock", MUTEX_DEFAULT, 0);
!     CV_INIT(&conn->conn_call_cv, "conn call cv", CV_DEFAULT, 0);
! #endif
      NETPRI;
      MUTEX_ENTER(&rx_connHashTable_lock);
!     cid = (rx_nextCid += RX_MAXCALLS);
!     conn->type = RX_CLIENT_CONNECTION;
!     conn->cid = cid;
!     conn->epoch = rx_epoch;
!     conn->peer = rxi_FindPeer(shost, sport, 0, 1);
!     conn->serviceId = sservice;
!     conn->securityObject = securityObject;
!     conn->securityData = (void *) 0;
!     conn->securityIndex = serviceSecurityIndex;
!     rx_SetConnDeadTime(conn, rx_connDeadTime);
!     conn->ackRate = RX_FAST_ACK_RATE;
!     conn->nSpecific = 0;
!     conn->specific = NULL;
!     conn->challengeEvent = NULL;
!     conn->delayedAbortEvent = NULL;
!     conn->abortCount = 0;
!     conn->error = 0;
      for (i = 0; i < RX_MAXCALLS; i++) {
! 	conn->twind[i] = rx_initSendWindow;
! 	conn->rwind[i] = rx_initReceiveWindow;
      }
  
!     RXS_NewConnection(securityObject, conn);
!     hashindex =
! 	CONN_HASH(shost, sport, conn->cid, conn->epoch, RX_CLIENT_CONNECTION);
! 
!     conn->refCount++;		/* no lock required since only this thread knows... */
!     conn->next = rx_connHashTable[hashindex];
!     rx_connHashTable[hashindex] = conn;
!     rx_MutexIncrement(rx_stats.nClientConns, rx_stats_mutex);
      MUTEX_EXIT(&rx_connHashTable_lock);
      USERPRI;
      return conn;
--- 747,823 ----
  		 int serviceSecurityIndex)
  {
      int hashindex, i;
!     afs_int32 cid, cix, nclones;
!     register struct rx_connection *conn, *tconn, *ptconn;
  
      SPLVAR;
  
      clock_NewTime();
      dpf(("rx_NewConnection(host %x, port %u, service %u, securityObject %x, serviceSecurityIndex %d)\n", ntohl(shost), ntohs(sport), sservice, securityObject, serviceSecurityIndex));
  
+ 	conn = tconn = 0;
+ 	nclones = rx_max_clones_per_connection;
+ 
      /* Vasilsi said: "NETPRI protects Cid and Alloc", but can this be true in
       * the case of kmem_alloc? */
! 
      NETPRI;
      MUTEX_ENTER(&rx_connHashTable_lock);
! 
!     /* send in the clones */
!     for(cix = 0; cix <= nclones; ++cix) {
! 	  
! 	  ptconn = tconn;
! 	  tconn = rxi_AllocConnection();
! 	  tconn->type = RX_CLIENT_CONNECTION;
! 	  tconn->epoch = rx_epoch;
! 	  tconn->peer = rxi_FindPeer(shost, sport, 0, 1);
! 	  tconn->serviceId = sservice;
! 	  tconn->securityObject = securityObject;
! 	  tconn->securityData = (void *) 0;
! 	  tconn->securityIndex = serviceSecurityIndex;
! 	  tconn->ackRate = RX_FAST_ACK_RATE;
! 	  tconn->nSpecific = 0;
! 	  tconn->specific = NULL;
! 	  tconn->challengeEvent = NULL;
! 	  tconn->delayedAbortEvent = NULL;
! 	  tconn->abortCount = 0;
! 	  tconn->error = 0;
      for (i = 0; i < RX_MAXCALLS; i++) {
! 	tconn->twind[i] = rx_initSendWindow;
! 	tconn->rwind[i] = rx_initReceiveWindow;
      }
+ 	  tconn->parent = 0;
+ 	  tconn->next_clone = 0;
+ 	  tconn->nclones = nclones;
+ 	  rx_SetConnDeadTime(tconn, rx_connDeadTime);
+ 		
+ 	  if(cix == 0) {
+ 		conn = tconn;
+ 	  } else {
+ 		tconn->flags |= RX_CLONED_CONNECTION;
+ 		tconn->parent = conn;
+ 		ptconn->next_clone = tconn;
+ 	  }
  
! 	  /* generic connection setup */
! #ifdef	RX_ENABLE_LOCKS
! 	  MUTEX_INIT(&tconn->conn_call_lock, "conn call lock", MUTEX_DEFAULT, 0);
! 	  MUTEX_INIT(&tconn->conn_data_lock, "conn data lock", MUTEX_DEFAULT, 0);
! 	  CV_INIT(&tconn->conn_call_cv, "conn call cv", CV_DEFAULT, 0);
! #endif
! 	  cid = (rx_nextCid += RX_MAXCALLS);
! 	  tconn->cid = cid;
! 	  RXS_NewConnection(securityObject, tconn);
! 	  hashindex =
! 		CONN_HASH(shost, sport, tconn->cid, tconn->epoch, 
! 				  RX_CLIENT_CONNECTION);
! 	  tconn->refCount++; /* no lock required since only this thread knows */
! 	  tconn->next = rx_connHashTable[hashindex];
! 	  rx_connHashTable[hashindex] = tconn;
! 	  rx_MutexIncrement(rx_stats.nClientConns, rx_stats_mutex);	
!     }
!     
      MUTEX_EXIT(&rx_connHashTable_lock);
      USERPRI;
      return conn;
***************
*** 798,807 ****
  void
  rx_SetConnDeadTime(register struct rx_connection *conn, register int seconds)
  {
!     /* The idea is to set the dead time to a value that allows several
!      * keepalives to be dropped without timing out the connection. */
!     conn->secondsUntilDead = MAX(seconds, 6);
!     conn->secondsUntilPing = conn->secondsUntilDead / 6;
  }
  
  int rxi_lowPeerRefCount = 0;
--- 826,839 ----
  void
  rx_SetConnDeadTime(register struct rx_connection *conn, register int seconds)
  {
!   /* The idea is to set the dead time to a value that allows several
!    * keepalives to be dropped without timing out the connection. */
!   struct rx_connection *tconn;
!   tconn = conn;
!   do {
! 	tconn->secondsUntilDead = MAX(seconds, 6);
! 	tconn->secondsUntilPing = tconn->secondsUntilDead / 6;
!   } while(tconn->next_clone && (tconn = tconn->next_clone));
  }
  
  int rxi_lowPeerRefCount = 0;
***************
*** 868,885 ****
  void
  rxi_DestroyConnection(register struct rx_connection *conn)
  {
!     MUTEX_ENTER(&rx_connHashTable_lock);
!     rxi_DestroyConnectionNoLock(conn);
!     /* conn should be at the head of the cleanup list */
!     if (conn == rx_connCleanup_list) {
  	rx_connCleanup_list = rx_connCleanup_list->next;
  	MUTEX_EXIT(&rx_connHashTable_lock);
  	rxi_CleanupConnection(conn);
!     }
  #ifdef RX_ENABLE_LOCKS
!     else {
  	MUTEX_EXIT(&rx_connHashTable_lock);
!     }
  #endif /* RX_ENABLE_LOCKS */
  }
  
--- 900,941 ----
  void
  rxi_DestroyConnection(register struct rx_connection *conn)
  {
!   register struct rx_connection *tconn, *dtconn;
! 
!   MUTEX_ENTER(&rx_connHashTable_lock);
!   
!   if(!(conn->flags & RX_CLONED_CONNECTION)) {
! 	tconn = conn->next_clone;
! 	conn->next_clone = 0; /* once */
! 	do {
! 	  if(tconn) {
! 		dtconn = tconn;
! 		tconn = tconn->next_clone;
! 		rxi_DestroyConnectionNoLock(dtconn);
! 		/* destroyed? */
! 		if (dtconn == rx_connCleanup_list) {
! 		  rx_connCleanup_list = rx_connCleanup_list->next;
! 		  MUTEX_EXIT(&rx_connHashTable_lock);
! 		  /* rxi_CleanupConnection will free tconn */	
! 		  rxi_CleanupConnection(dtconn);
! 		  MUTEX_ENTER(&rx_connHashTable_lock);
! 		  (conn->nclones)--;
! 		}
! 	  }
! 	} while(tconn);
!   }
! 
!   rxi_DestroyConnectionNoLock(conn);
!   /* conn should be at the head of the cleanup list */
!   if (conn == rx_connCleanup_list) {
  	rx_connCleanup_list = rx_connCleanup_list->next;
  	MUTEX_EXIT(&rx_connHashTable_lock);
  	rxi_CleanupConnection(conn);
!   }
  #ifdef RX_ENABLE_LOCKS
!   else {
  	MUTEX_EXIT(&rx_connHashTable_lock);
!   }
  #endif /* RX_ENABLE_LOCKS */
  }
  
***************
*** 1065,1070 ****
--- 1121,1127 ----
  {
      register int i;
      register struct rx_call *call;
+ 	register struct rx_connection *tconn;
      struct clock queueTime;
      SPLVAR;
  
***************
*** 1107,1145 ****
      } 
      MUTEX_EXIT(&conn->conn_data_lock);
  
      for (;;) {
! 	for (i = 0; i < RX_MAXCALLS; i++) {
! 	    call = conn->call[i];
! 	    if (call) {
! 		MUTEX_ENTER(&call->lock);
! 		if (call->state == RX_STATE_DALLY) {
! 		    rxi_ResetCall(call, 0);
! 		    (*call->callNumber)++;
! 		    break;
  		}
! 		MUTEX_EXIT(&call->lock);
! 	    } else {
! 		call = rxi_NewCall(conn, i);
! 		break;
! 	    }
! 	}
! 	if (i < RX_MAXCALLS) {
! 	    break;
! 	}
! 	MUTEX_ENTER(&conn->conn_data_lock);
! 	conn->flags |= RX_CONN_MAKECALL_WAITING;
! 	conn->makeCallWaiters++;
! 	MUTEX_EXIT(&conn->conn_data_lock);
  
  #ifdef	RX_ENABLE_LOCKS
! 	CV_WAIT(&conn->conn_call_cv, &conn->conn_call_lock);
  #else
! 	osi_rxSleep(conn);
  #endif
! 	MUTEX_ENTER(&conn->conn_data_lock);
! 	conn->makeCallWaiters--;
! 	MUTEX_EXIT(&conn->conn_data_lock);
!     }
      /*
       * Wake up anyone else who might be giving us a chance to
       * run (see code above that avoids resource starvation).
--- 1164,1214 ----
      } 
      MUTEX_EXIT(&conn->conn_data_lock);
  
+ 	/* search for next free call on this connection or 
+ 	 * its clones, if any */
      for (;;) {
! 		tconn = conn;
! 		do {
! 			for (i = 0; i < RX_MAXCALLS; i++) {
! 				call = tconn->call[i];
! 				if (call) {
! 					MUTEX_ENTER(&call->lock);
! 					if (call->state == RX_STATE_DALLY) {
! 						rxi_ResetCall(call, 0);
! 						(*call->callNumber)++;
! 						goto f_call;
! 					}
! 					MUTEX_EXIT(&call->lock);
! 				} else {
! 					call = rxi_NewCall(tconn, i);
! 					goto f_call;
! 				}
! 			} /* for i < RX_MAXCALLS */
! 		} while (tconn->next_clone && (tconn = tconn->next_clone));
! 
! 	f_call:
! 
! 		if (i < RX_MAXCALLS) {
! 			break;
  		}
! 
! 		/* to be here, all available calls for this connection (and all
! 		 * its clones) must be in use */
! 
! 		MUTEX_ENTER(&conn->conn_data_lock);
! 		conn->flags |= RX_CONN_MAKECALL_WAITING;
! 		conn->makeCallWaiters++;
! 		MUTEX_EXIT(&conn->conn_data_lock);
  
  #ifdef	RX_ENABLE_LOCKS
! 		CV_WAIT(&conn->conn_call_cv, &conn->conn_call_lock);
  #else
! 		osi_rxSleep(conn);
  #endif
! 		MUTEX_ENTER(&conn->conn_data_lock);
! 		conn->makeCallWaiters--;
! 		MUTEX_EXIT(&conn->conn_data_lock);
!     } /* for ;; */
      /*
       * Wake up anyone else who might be giving us a chance to
       * run (see code above that avoids resource starvation).
***************
*** 1328,1333 ****
--- 1397,1403 ----
  	    service->minProcs = 0;
  	    service->maxProcs = 1;
  	    service->idleDeadTime = 60;
+ 	    service->idleDeadErr = 0;
  	    service->connDeadTime = rx_connDeadTime;
  	    service->executeRequestProc = serviceProc;
  	    service->checkReach = 0;
***************
*** 2260,2265 ****
--- 2330,2372 ----
      osi_Free(addr, size);
  }
  
+ void 
+ rxi_SetPeerMtu(register afs_uint32 host, register afs_uint32 port, int mtu)
+ {
+     struct rx_peer **peer_ptr, **peer_end;
+     int hashIndex;
+ 
+     MUTEX_ENTER(&rx_peerHashTable_lock);
+     if (port == 0) {
+        for (peer_ptr = &rx_peerHashTable[0], peer_end =
+                 &rx_peerHashTable[rx_hashTableSize]; peer_ptr < peer_end;
+             peer_ptr++) {
+            struct rx_peer *peer, *next;
+            for (peer = *peer_ptr; peer; peer = next) {
+                next = peer->next;
+                if (host == peer->host) {
+                    MUTEX_ENTER(&peer->peer_lock);
+                    peer->ifMTU=MIN(mtu, peer->ifMTU);
+                    peer->natMTU = rxi_AdjustIfMTU(peer->ifMTU);
+                    MUTEX_EXIT(&peer->peer_lock);
+                }
+            }
+        }
+     } else {
+        struct rx_peer *peer, *next;
+        hashIndex = PEER_HASH(host, port);
+        for (peer = rx_peerHashTable[hashIndex]; peer; peer = peer->next) {
+            if ((peer->host == host) && (peer->port == port)) {
+                MUTEX_ENTER(&peer->peer_lock);
+                peer->ifMTU=MIN(mtu, peer->ifMTU);
+                peer->natMTU = rxi_AdjustIfMTU(peer->ifMTU);
+                MUTEX_EXIT(&peer->peer_lock);
+            }
+        }
+     }
+     MUTEX_EXIT(&rx_peerHashTable_lock);
+ }
+ 
  /* Find the peer process represented by the supplied (host,port)
   * combination.  If there is no appropriate active peer structure, a
   * new one will be allocated and initialized 
***************
*** 2389,2394 ****
--- 2496,2502 ----
  	conn->specific = NULL;
  	rx_SetConnDeadTime(conn, service->connDeadTime);
  	rx_SetConnIdleDeadTime(conn, service->idleDeadTime);
+ 	rx_SetServerConnIdleDeadErr(conn, service->idleDeadErr);
  	for (i = 0; i < RX_MAXCALLS; i++) {
  	    conn->twind[i] = rx_initSendWindow;
  	    conn->rwind[i] = rx_initReceiveWindow;
***************
*** 4922,4928 ****
      /* Update last send time for this call (for keep-alive
       * processing), and for the connection (so that we can discover
       * idle connections) */
!     conn->lastSendTime = call->lastSendTime = clock_Sec();
  }
  
  /* When sending packets we need to follow these rules:
--- 5030,5036 ----
      /* Update last send time for this call (for keep-alive
       * processing), and for the connection (so that we can discover
       * idle connections) */
!     call->lastSendData = conn->lastSendTime = call->lastSendTime = clock_Sec();
  }
  
  /* When sending packets we need to follow these rules:
***************
*** 5386,5391 ****
--- 5494,5502 ----
       * processing), and for the connection (so that we can discover
       * idle connections) */
      conn->lastSendTime = call->lastSendTime = clock_Sec();
+     /* Don't count keepalives here, so idleness can be tracked. */
+     if (p->header.type != RX_PACKET_TYPE_ACK)
+ 	call->lastSendData = call->lastSendTime;
  }
  
  
***************
*** 5427,5432 ****
--- 5538,5569 ----
       * number of seconds. */
      if (now > (call->lastReceiveTime + deadTime)) {
  	if (call->state == RX_STATE_ACTIVE) {
+ #ifdef ADAPT_PMTU
+ #if defined(KERNEL) && defined(AFS_SUN57_ENV)
+ 	    ire_t *ire;
+ #if defined(AFS_SUN510_ENV) && defined(GLOBAL_NETSTACKID)
+ 	    netstack_t *ns =  netstack_find_by_stackid(GLOBAL_NETSTACKID);
+ 	    ip_stack_t *ipst = ns->netstack_ip;
+ #endif
+ 	    ire = ire_cache_lookup(call->conn->peer->host
+ #if defined(AFS_SUN510_ENV) && defined(ALL_ZONES)
+ 				   , ALL_ZONES
+ #if defined(AFS_SUN510_ENV) && (defined(ICL_3_ARG) || defined(GLOBAL_NETSTACKID))
+ 				   , NULL
+ #if defined(AFS_SUN510_ENV) && defined(GLOBAL_NETSTACKID)
+ 				   , ipst
+ #endif
+ #endif
+ #endif
+ 		);
+ 	    
+ 	    if (ire && ire->ire_max_frag > 0)
+ 		rxi_SetPeerMtu(call->conn->peer->host, 0, ire->ire_max_frag);
+ #if defined(GLOBAL_NETSTACKID)
+ 	    netstack_rele(ns);
+ #endif
+ #endif
+ #endif /* ADAPT_PMTU */
  	    rxi_CallError(call, RX_CALL_DEAD);
  	    return -1;
  	} else {
***************
*** 5459,5464 ****
--- 5596,5608 ----
  	    return -1;
  	}
      }
+     if (call->lastSendData && conn->idleDeadTime && (conn->idleDeadErr != 0)
+         && ((call->lastSendData + conn->idleDeadTime) < now)) {
+ 	if (call->state == RX_STATE_ACTIVE) {
+ 	    rxi_CallError(call, conn->idleDeadErr);
+ 	    return -1;
+ 	}
+     }
      /* see if we have a hard timeout */
      if (conn->hardDeadTime
  	&& (now > (conn->hardDeadTime + call->startTime.sec))) {
Index: openafs/src/rx/rx.h
diff -c openafs/src/rx/rx.h:1.28.4.8 openafs/src/rx/rx.h:1.28.4.8.2.2
*** openafs/src/rx/rx.h:1.28.4.8	Thu May  8 17:25:58 2008
--- openafs/src/rx/rx.h	Tue May 20 16:24:56 2008
***************
*** 145,150 ****
--- 145,153 ----
  /* Define procedure to set service dead time */
  #define rx_SetIdleDeadTime(service,time) ((service)->idleDeadTime = (time))
  
+ /* Define error to return in server connections when failing to answer */
+ #define rx_SetServerIdleDeadErr(service,err) ((service)->idleDeadErr = (err))
+ 
  /* Define procedures for getting and setting before and after execute-request procs */
  #define rx_SetAfterProc(service,proc) ((service)->afterProc = (proc))
  #define rx_SetBeforeProc(service,proc) ((service)->beforeProc = (proc))
***************
*** 165,170 ****
--- 168,174 ----
  /* Set connection hard and idle timeouts for a connection */
  #define rx_SetConnHardDeadTime(conn, seconds) ((conn)->hardDeadTime = (seconds))
  #define rx_SetConnIdleDeadTime(conn, seconds) ((conn)->idleDeadTime = (seconds))
+ #define rx_SetServerConnIdleDeadErr(conn,err) ((conn)->idleDeadErr = (err))
  
  /* Set the overload threshold and the overload error */
  #define rx_SetBusyThreshold(threshold, code) (rx_BusyThreshold=(threshold),rx_BusyError=(code))
***************
*** 206,211 ****
--- 210,229 ----
  #define rx_EnableHotThread()		(rx_enable_hot_thread = 1)
  #define rx_DisableHotThread()		(rx_enable_hot_thread = 0)
  
+ /* Macros to set max connection clones (each allows RX_MAXCALLS 
+  * outstanding calls */
+ 
+ #define rx_SetMaxCalls(v) \
+ do {\
+ 	rx_SetCloneMax(v/4); \
+ } while(0);
+ 
+ #define rx_SetCloneMax(v) \
+ do {\
+ 	if(v < RX_HARD_MAX_CLONES) \
+ 		rx_max_clones_per_connection = v; \
+ } while(0);
+ 
  #define rx_PutConnection(conn) rx_DestroyConnection(conn)
  
  /* A connection is an authenticated communication path, allowing 
***************
*** 216,222 ****
      struct rx_peer_rx_lock *peer;
  #else
  struct rx_connection {
!     struct rx_connection *next;	/*  on hash chain _or_ free list */
      struct rx_peer *peer;
  #endif
  #ifdef	RX_ENABLE_LOCKS
--- 234,242 ----
      struct rx_peer_rx_lock *peer;
  #else
  struct rx_connection {
!     struct rx_connection *next;	/* on hash chain _or_ free list */
!     struct rx_connection *parent; /* primary connection, if this is a clone */
!     struct rx_connection *next_clone; /* next in list of clones */
      struct rx_peer *peer;
  #endif
  #ifdef	RX_ENABLE_LOCKS
***************
*** 224,229 ****
--- 244,250 ----
      afs_kcondvar_t conn_call_cv;
      afs_kmutex_t conn_data_lock;	/* locks packet data */
  #endif
+     afs_uint32 nclones; /* count of clone connections (if not a clone) */
      afs_uint32 epoch;		/* Process start time of client side of connection */
      afs_uint32 cid;		/* Connection id (call channel is bottom bits) */
      afs_int32 error;		/* If this connection is in error, this is it */
***************
*** 265,270 ****
--- 286,292 ----
      u_short idleDeadTime;	/* max time a call can be idle (no data) */
      u_char ackRate;		/* how many packets between ack requests */
      u_char makeCallWaiters;	/* how many rx_NewCalls are waiting */
+     afs_int32 idleDeadErr;
      int nSpecific;		/* number entries in specific data */
      void **specific;		/* pointer to connection specific data */
  };
***************
*** 309,314 ****
--- 331,337 ----
      u_short connDeadTime;	/* Seconds until a client of this service will be declared dead, if it is not responding */
      u_short idleDeadTime;	/* Time a server will wait for I/O to start up again */
      u_char checkReach;		/* Check for asymmetric clients? */
+     afs_int32 idleDeadErr;
  };
  
  #endif /* KDUMP_RX_LOCK */
***************
*** 421,426 ****
--- 444,450 ----
  #define RX_CONN_RESET		   16	/* connection is reset, remove */
  #define RX_CONN_BUSY               32	/* connection is busy; don't delete */
  #define RX_CONN_ATTACHWAIT	   64	/* attach waiting for peer->lastReach */
+ #define RX_CLONED_CONNECTION	  128   /* connection is a clone */
  
  /* Type of connection, client or server */
  #define	RX_CLIENT_CONNECTION	0
***************
*** 505,510 ****
--- 529,535 ----
      int abortCount;		/* number of times last error was sent */
      u_int lastSendTime;		/* Last time a packet was sent on this call */
      u_int lastReceiveTime;	/* Last time a packet was received for this call */
+     u_int lastSendData;		/* Last time a nonping was sent on this call */
      void (*arrivalProc) (register struct rx_call * call, register void * mh, register int index);	/* Procedure to call when reply is received */
      void *arrivalProcHandle;	/* Handle to pass to replyFunc */
      int arrivalProcArg;         /* Additional arg to pass to reply Proc */
Index: openafs/src/rx/rx_globals.h
diff -c openafs/src/rx/rx_globals.h:1.21.2.8 openafs/src/rx/rx_globals.h:1.21.2.8.2.2
*** openafs/src/rx/rx_globals.h:1.21.2.8	Thu May  8 17:25:58 2008
--- openafs/src/rx/rx_globals.h	Tue May 20 17:59:43 2008
***************
*** 397,403 ****
   * This is provided for backward compatibility with peers which may be unable
   * to swallow anything larger. THIS MUST NEVER DECREASE WHILE AN APPLICATION
   * IS RUNNING! */
! EXT afs_uint32 rx_maxReceiveSize GLOBALSINIT(OLD_MAX_PACKET_SIZE * RX_MAX_FRAGS +
  				      UDP_HDR_SIZE * (RX_MAX_FRAGS - 1));
  
  /* this is the maximum packet size that the user wants us to receive */
--- 397,403 ----
   * This is provided for backward compatibility with peers which may be unable
   * to swallow anything larger. THIS MUST NEVER DECREASE WHILE AN APPLICATION
   * IS RUNNING! */
! EXT afs_uint32 rx_maxReceiveSize GLOBALSINIT(_OLD_MAX_PACKET_SIZE * RX_MAX_FRAGS +
  				      UDP_HDR_SIZE * (RX_MAX_FRAGS - 1));
  
  /* this is the maximum packet size that the user wants us to receive */
***************
*** 591,594 ****
--- 591,609 ----
   */
  EXT int rx_enable_hot_thread GLOBALSINIT(0);
  
+ /*
+  * Set rx_max_clones_per_connection to a value > 0 to enable connection clone 
+  * workaround to RX_MAXCALLS limit.
+  */
+  
+ #define RX_HARD_MAX_CLONES 10
+ 
+ /* Should be syncd before 1.6.0 */
+ #if defined(AFS_NT40_ENV)
+ EXT int rx_max_clones_per_connection GLOBALSINIT(0);
+ #else
+ EXT int rx_max_clones_per_connection GLOBALSINIT(2);
+ #endif
+ 
+ EXT int RX_IPUDP_SIZE GLOBALSINIT(_RX_IPUDP_SIZE);
  #endif /* AFS_RX_GLOBALS_H */
Index: openafs/src/rx/rx_lwp.c
diff -c openafs/src/rx/rx_lwp.c:1.19.4.2 openafs/src/rx/rx_lwp.c:1.19.4.2.2.1
*** openafs/src/rx/rx_lwp.c:1.19.4.2	Mon Mar 10 18:32:34 2008
--- openafs/src/rx/rx_lwp.c	Tue May 20 17:59:43 2008
***************
*** 22,28 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_lwp.c,v 1.19.4.2 2008/03/10 22:32:34 shadow Exp $");
  
  # include <sys/types.h>		/* fd_set on older platforms */
  # include <errno.h>
--- 22,28 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_lwp.c,v 1.19.4.2.2.1 2008/05/20 21:59:43 shadow Exp $");
  
  # include <sys/types.h>		/* fd_set on older platforms */
  # include <errno.h>
***************
*** 428,433 ****
--- 428,437 ----
  int
  rxi_Recvmsg(osi_socket socket, struct msghdr *msg_p, int flags)
  {
+ #if defined(HAVE_LINUX_ERRQUEUE_H) && defined(ADAPT_PMTU)
+     while((rxi_HandleSocketError(socket)) > 0)
+ 	;
+ #endif
      return recvmsg(socket, msg_p, flags);
  }
  
***************
*** 451,456 ****
--- 455,464 ----
  	    }
  	    FD_SET(socket, sfds);
  	}
+ #if defined(HAVE_LINUX_ERRQUEUE_H) && defined(ADAPT_PMTU)
+ 	while((rxi_HandleSocketError(socket)) > 0)
+ 	  ;
+ #endif
  #ifdef AFS_NT40_ENV
  	if (WSAGetLastError())
  #elif defined(AFS_LINUX22_ENV)
Index: openafs/src/rx/rx_packet.c
diff -c openafs/src/rx/rx_packet.c:1.62.2.11 openafs/src/rx/rx_packet.c:1.62.2.11.2.1
*** openafs/src/rx/rx_packet.c:1.62.2.11	Tue Mar 11 14:27:39 2008
--- openafs/src/rx/rx_packet.c	Tue May 20 17:59:43 2008
***************
*** 15,21 ****
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_packet.c,v 1.62.2.11 2008/03/11 18:27:39 jaltman Exp $");
  
  #ifdef KERNEL
  #if defined(UKERNEL)
--- 15,21 ----
  #endif
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_packet.c,v 1.62.2.11.2.1 2008/05/20 21:59:43 shadow Exp $");
  
  #ifdef KERNEL
  #if defined(UKERNEL)
***************
*** 2630,2635 ****
--- 2630,2637 ----
      int adjMTU;
      int frags;
  
+     if (rxi_nRecvFrags == 1 && rxi_nSendFrags == 1)
+         return mtu;
      adjMTU = RX_HEADER_SIZE + RX_JUMBOBUFFERSIZE + RX_JUMBOHEADERSIZE;
      if (mtu <= adjMTU) {
  	return mtu;
Index: openafs/src/rx/rx_packet.h
diff -c openafs/src/rx/rx_packet.h:1.14 openafs/src/rx/rx_packet.h:1.14.8.1
*** openafs/src/rx/rx_packet.h:1.14	Sun May 29 23:39:50 2005
--- openafs/src/rx/rx_packet.h	Tue May 20 17:59:43 2008
***************
*** 51,57 ****
  #define IPv6_FRAG_HDR_SIZE	 8	/* IPv6 Fragment Header */
  #define UDP_HDR_SIZE             8	/* UDP Header */
  #define	RX_IP_SIZE		(IPv6_HDR_SIZE + IPv6_FRAG_HDR_SIZE)
! #define	RX_IPUDP_SIZE		(RX_IP_SIZE + UDP_HDR_SIZE)
  
  /* REMOTE_PACKET_SIZE is currently the same as local.  This is because REMOTE
   * is defined much too generally for my tastes, and includes the case of 
--- 51,57 ----
  #define IPv6_FRAG_HDR_SIZE	 8	/* IPv6 Fragment Header */
  #define UDP_HDR_SIZE             8	/* UDP Header */
  #define	RX_IP_SIZE		(IPv6_HDR_SIZE + IPv6_FRAG_HDR_SIZE)
! #define	_RX_IPUDP_SIZE		(RX_IP_SIZE + UDP_HDR_SIZE)
  
  /* REMOTE_PACKET_SIZE is currently the same as local.  This is because REMOTE
   * is defined much too generally for my tastes, and includes the case of 
***************
*** 102,112 ****
--- 102,116 ----
  /* The minimum MTU for an IP network is 576 bytes including headers */
  #define RX_MIN_PACKET_SIZE      (576 - RX_IPUDP_SIZE)
  #define	RX_PP_PACKET_SIZE	RX_MIN_PACKET_SIZE
+ #define _RX_MIN_PACKET_SIZE      (576 - _RX_IPUDP_SIZE)
+ #define	_RX_PP_PACKET_SIZE	_RX_MIN_PACKET_SIZE
  
  #define	OLD_MAX_PACKET_SIZE	(1500 - RX_IPUDP_SIZE)
+ #define	_OLD_MAX_PACKET_SIZE	(1500 - _RX_IPUDP_SIZE)
  
  /* if the other guy is not on the local net, use this size */
  #define	RX_REMOTE_PACKET_SIZE	(1500 - RX_IPUDP_SIZE)
+ #define	_RX_REMOTE_PACKET_SIZE	(1500 - _RX_IPUDP_SIZE)
  
  /* for now, never send more data than this */
  #define	RX_MAX_PACKET_SIZE	16384
Index: openafs/src/rx/rx_prototypes.h
diff -c openafs/src/rx/rx_prototypes.h:1.29.4.9 openafs/src/rx/rx_prototypes.h:1.29.4.9.2.1
*** openafs/src/rx/rx_prototypes.h:1.29.4.9	Mon Mar 17 11:38:28 2008
--- openafs/src/rx/rx_prototypes.h	Tue May 20 17:59:43 2008
***************
*** 83,88 ****
--- 83,90 ----
  
  extern char *rxi_Alloc(register size_t size);
  extern void rxi_Free(void *addr, register size_t size);
+ extern void rxi_SetPeerMtu(register afs_uint32 host, register afs_uint32 port,
+             int mtu);
  extern struct rx_peer *rxi_FindPeer(register afs_uint32 host,
  				    register u_short port,
  				    struct rx_peer *origPeer, int create);
***************
*** 584,589 ****
--- 586,592 ----
  extern void osi_AssertFailU(const char *expr, const char *file, int line);
  extern int rx_getAllAddr(afs_int32 * buffer, int maxSize);
  extern void rxi_InitPeerParams(struct rx_peer *pp);
+ extern int rxi_HandleSocketError(int socket);
  
  #if defined(AFS_AIX32_ENV) && !defined(KERNEL)
  extern void *osi_Alloc(afs_int32 x);
Index: openafs/src/rx/rx_pthread.c
diff -c openafs/src/rx/rx_pthread.c:1.24.4.5 openafs/src/rx/rx_pthread.c:1.24.4.5.2.1
*** openafs/src/rx/rx_pthread.c:1.24.4.5	Mon Mar 10 18:32:34 2008
--- openafs/src/rx/rx_pthread.c	Tue May 20 17:59:43 2008
***************
*** 19,25 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_pthread.c,v 1.24.4.5 2008/03/10 22:32:34 shadow Exp $");
  
  #include <sys/types.h>
  #include <errno.h>
--- 19,25 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_pthread.c,v 1.24.4.5.2.1 2008/05/20 21:59:43 shadow Exp $");
  
  #include <sys/types.h>
  #include <errno.h>
***************
*** 412,417 ****
--- 412,421 ----
  rxi_Recvmsg(osi_socket socket, struct msghdr *msg_p, int flags)
  {
      int ret;
+ #if defined(HAVE_LINUX_ERRQUEUE_H) && defined(ADAPT_PMTU)
+     while((rxi_HandleSocketError(socket)) > 0)
+       ;
+ #endif
      ret = recvmsg(socket, msg_p, flags);
      return ret;
  }
Index: openafs/src/rx/rx_user.c
diff -c openafs/src/rx/rx_user.c:1.24.4.2 openafs/src/rx/rx_user.c:1.24.4.2.2.1
*** openafs/src/rx/rx_user.c:1.24.4.2	Tue Oct 30 11:16:45 2007
--- openafs/src/rx/rx_user.c	Tue May 20 17:59:43 2008
***************
*** 13,19 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_user.c,v 1.24.4.2 2007/10/30 15:16:45 shadow Exp $");
  
  # include <sys/types.h>
  # include <errno.h>
--- 13,19 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/rx_user.c,v 1.24.4.2.2.1 2008/05/20 21:59:43 shadow Exp $");
  
  # include <sys/types.h>
  # include <errno.h>
***************
*** 95,102 ****
--- 95,114 ----
      struct sockaddr_in taddr;
      char *name = "rxi_GetUDPSocket: ";
  #ifdef AFS_LINUX22_ENV
+ #if defined(ADAPT_PMTU)
+     int pmtu=IP_PMTUDISC_WANT;
+     int recverr=1;
+ #else
      int pmtu=IP_PMTUDISC_DONT;
  #endif
+ #endif
+ #if defined(HAVE_LINUX_ERRQUEUE_H) && defined(ADAPT_PMTU)
+ #include <linux/types.h>
+ #include <linux/errqueue.h>
+ #ifndef IP_MTU
+ #define IP_MTU 14
+ #endif
+ #endif
  
  #if !defined(AFS_NT40_ENV) && !defined(AFS_DJGPP_ENV)
      if (ntohs(port) >= IPPORT_RESERVED && ntohs(port) < IPPORT_USERRESERVED) {
***************
*** 180,187 ****
  
  #ifdef AFS_LINUX22_ENV
      setsockopt(socketFd, SOL_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
  #endif
- 
      if (rxi_Listen(socketFd) < 0) {
  	goto error;
      }
--- 192,201 ----
  
  #ifdef AFS_LINUX22_ENV
      setsockopt(socketFd, SOL_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
+ #if defined(ADAPT_PMTU)
+     setsockopt(socketFd, SOL_IP, IP_RECVERR, &recverr, sizeof(recverr));
+ #endif
  #endif
      if (rxi_Listen(socketFd) < 0) {
  	goto error;
      }
***************
*** 614,619 ****
--- 628,637 ----
      afs_uint32 ppaddr;
      u_short rxmtu;
      int ix;
+ #if defined(ADAPT_PMTU) && defined(IP_MTU)
+     int sock;
+     struct sockaddr_in addr;
+ #endif
  
  
  
***************
*** 665,670 ****
--- 683,704 ----
      pp->timeout.sec = 2;
      pp->ifMTU = MIN(rx_MyMaxSendSize, OLD_MAX_PACKET_SIZE);
  #endif /* ADAPT_MTU */
+ #if defined(ADAPT_PMTU) && defined(IP_MTU)
+     sock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+     if (sock >= 0) {
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = pp->host;
+       addr.sin_port = pp->port;
+       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+ 	int mtu=0;
+         socklen_t s = sizeof(mtu);
+ 	if (getsockopt(sock, SOL_IP, IP_MTU, &mtu, &s)== 0) {
+ 	  pp->ifMTU = MIN(mtu - RX_IPUDP_SIZE, pp->ifMTU);
+ 	}
+       }
+       close(sock);
+     }
+ #endif
      pp->ifMTU = rxi_AdjustIfMTU(pp->ifMTU);
      pp->maxMTU = OLD_MAX_PACKET_SIZE;	/* for compatibility with old guys */
      pp->natMTU = MIN((int)pp->ifMTU, OLD_MAX_PACKET_SIZE);
***************
*** 697,699 ****
--- 731,784 ----
  {
      rx_MyMaxSendSize = rx_maxReceiveSizeUser = rx_maxReceiveSize = mtu;
  }
+ 
+ #if defined(HAVE_LINUX_ERRQUEUE_H) && defined(ADAPT_PMTU)
+ int
+ rxi_HandleSocketError(int socket)
+ {
+     struct msghdr msg;
+     struct cmsghdr *cmsg;
+     struct sock_extended_err *err;
+     struct sockaddr_in addr;
+     struct sockaddr *offender;
+     char controlmsgbuf[256];
+     int ret=0;
+     int code;
+ 
+     msg.msg_name = &addr;
+     msg.msg_namelen = sizeof(addr);
+     msg.msg_iov = NULL;
+     msg.msg_iovlen = 0;
+     msg.msg_control = controlmsgbuf;
+     msg.msg_controllen = 256;
+     msg.msg_flags = 0;
+     code = recvmsg(socket, &msg, MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC);
+ 
+     if (code < 0 || !(msg.msg_flags & MSG_ERRQUEUE))
+         goto out;
+ 
+     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+        if ((char *)cmsg - controlmsgbuf > msg.msg_controllen - CMSG_SPACE(0) ||
+            (char *)cmsg - controlmsgbuf > msg.msg_controllen - CMSG_SPACE(cmsg->cmsg_len) ||
+ 	   cmsg->cmsg_len == 0) {
+ 	   cmsg = 0;
+            break;
+ 	}
+         if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
+             break;
+     }
+     if (!cmsg)
+         goto out;
+     ret=1;
+     err =(struct sock_extended_err *) CMSG_DATA(cmsg);
+     
+     if (err->ee_errno == EMSGSIZE && err->ee_info >= 68) {
+         rxi_SetPeerMtu(addr.sin_addr.s_addr, addr.sin_port,
+                        err->ee_info - RX_IPUDP_SIZE);
+     }
+     /* other DEST_UNREACH's and TIME_EXCEEDED should be dealt with too */
+     
+ out:
+     return ret;
+ }
+ #endif
Index: openafs/src/rx/rxperf.c
diff -c openafs/src/rx/rxperf.c:1.2 openafs/src/rx/rxperf.c:1.2.32.1
*** openafs/src/rx/rxperf.c:1.2	Tue Jul 15 19:16:12 2003
--- openafs/src/rx/rxperf.c	Tue May 20 17:59:43 2008
***************
*** 32,40 ****
   * SUCH DAMAGE.
   */
  
! #ifdef HAVE_CONFIG_H
! #include <config.h>
! #endif
  
  /* 
  nn * We are using getopt since we want it to be possible to link to
--- 32,38 ----
   * SUCH DAMAGE.
   */
  
! #include <afsconfig.h>
  
  /* 
  nn * We are using getopt since we want it to be possible to link to
***************
*** 42,48 ****
   */
  
  #ifdef RCSID
! RCSID("$Id: rxperf.c,v 1.2 2003/07/15 23:16:12 shadow Exp $");
  #endif
  
  #include <stdarg.h>
--- 40,46 ----
   */
  
  #ifdef RCSID
! RCSID("$Id: rxperf.c,v 1.2.32.1 2008/05/20 21:59:43 shadow Exp $");
  #endif
  
  #include <stdarg.h>
***************
*** 57,65 ****
--- 55,71 ----
  #include <stdio.h>
  #include <stdlib.h>
  #include <errno.h>
+ #ifdef HAVE_STRING_H
+ #include <string.h>
+ #else
+ #ifdef HAVE_STRINGS_H
  #include <strings.h>
+ #endif
+ #endif
  #include <assert.h>
+ #ifdef HAVE_UNISTD_H
  #include <unistd.h>
+ #endif
  #include <signal.h>
  #ifdef HAVE_ERRX
  #include <err.h>		/* not stricly right, but if we have a errx() there
***************
*** 311,317 ****
  
      DBFPRINT(("got a request\n"));
  
!     if (rx_Read(call, &version, 4) != 4) {
  	warn("rx_Read failed to read version");
  	return -1;
      }
--- 317,323 ----
  
      DBFPRINT(("got a request\n"));
  
!     if (rx_Read32(call, &version) != 4) {
  	warn("rx_Read failed to read version");
  	return -1;
      }
***************
*** 321,333 ****
  	return -1;
      }
  
!     if (rx_Read(call, &command, 4) != 4) {
  	warnx("rx_Read failed to read command");
  	return -1;
      }
      command = ntohl(command);
  
!     if (rx_Read(call, &data, 4) != 4) {
  	warnx("rx_Read failed to read size");
  	return -1;
      }
--- 327,339 ----
  	return -1;
      }
  
!     if (rx_Read32(call, &command) != 4) {
  	warnx("rx_Read failed to read command");
  	return -1;
      }
      command = ntohl(command);
  
!     if (rx_Read32(call, &data) != 4) {
  	warnx("rx_Read failed to read size");
  	return -1;
      }
***************
*** 337,343 ****
  	return -1;
      }
  
!     if (rx_Read(call, &data, 4) != 4) {
  	warnx("rx_Read failed to write size");
  	return -1;
      }
--- 343,349 ----
  	return -1;
      }
  
!     if (rx_Read32(call, &data) != 4) {
  	warnx("rx_Read failed to write size");
  	return -1;
      }
***************
*** 351,357 ****
      case RX_PERF_SEND:
  	DBFPRINT(("got a send request\n"));
  
! 	if (rx_Read(call, &bytes, 4) != 4) {
  	    warnx("rx_Read failed to read bytes");
  	    return -1;
  	}
--- 357,363 ----
      case RX_PERF_SEND:
  	DBFPRINT(("got a send request\n"));
  
! 	if (rx_Read32(call, &bytes) != 4) {
  	    warnx("rx_Read failed to read bytes");
  	    return -1;
  	}
***************
*** 361,367 ****
  	readbytes(call, bytes);
  
  	data = htonl(RXPERF_MAGIC_COOKIE);
! 	if (rx_Write(call, &data, 4) != 4) {
  	    warnx("rx_Write failed when sending back result");
  	    return -1;
  	}
--- 367,373 ----
  	readbytes(call, bytes);
  
  	data = htonl(RXPERF_MAGIC_COOKIE);
! 	if (rx_Write32(call, &data) != 4) {
  	    warnx("rx_Write failed when sending back result");
  	    return -1;
  	}
***************
*** 371,382 ****
      case RX_PERF_RPC:
  	DBFPRINT(("got a rpc request, reading commands\n"));
  
! 	if (rx_Read(call, &recvb, 4) != 4) {
  	    warnx("rx_Read failed to read recvbytes");
  	    return -1;
  	}
  	recvb = ntohl(recvb);
! 	if (rx_Read(call, &sendb, 4) != 4) {
  	    warnx("rx_Read failed to read sendbytes");
  	    return -1;
  	}
--- 377,388 ----
      case RX_PERF_RPC:
  	DBFPRINT(("got a rpc request, reading commands\n"));
  
! 	if (rx_Read32(call, &recvb) != 4) {
  	    warnx("rx_Read failed to read recvbytes");
  	    return -1;
  	}
  	recvb = ntohl(recvb);
! 	if (rx_Read32(call, &sendb) != 4) {
  	    warnx("rx_Read failed to read sendbytes");
  	    return -1;
  	}
***************
*** 396,409 ****
  	DBFPRINT(("done\n"));
  
  	data = htonl(RXPERF_MAGIC_COOKIE);
! 	if (rx_Write(call, &data, 4) != 4) {
  	    warnx("rx_Write failed when sending back magic cookie");
  	    return -1;
  	}
  
  	break;
      case RX_PERF_FILE:
! 	if (rx_Read(call, &data, 4) != 4)
  	    errx(1, "failed to read num from client");
  	num = ntohl(data);
  
--- 402,415 ----
  	DBFPRINT(("done\n"));
  
  	data = htonl(RXPERF_MAGIC_COOKIE);
! 	if (rx_Write32(call, &data) != 4) {
  	    warnx("rx_Write failed when sending back magic cookie");
  	    return -1;
  	}
  
  	break;
      case RX_PERF_FILE:
! 	if (rx_Read32(call, &data) != 4)
  	    errx(1, "failed to read num from client");
  	num = ntohl(data);
  
***************
*** 436,442 ****
      case RX_PERF_RECV:
  	DBFPRINT(("got a recv request\n"));
  
! 	if (rx_Read(call, &bytes, 4) != 4) {
  	    warnx("rx_Read failed to read bytes");
  	    return -1;
  	}
--- 442,448 ----
      case RX_PERF_RECV:
  	DBFPRINT(("got a recv request\n"));
  
! 	if (rx_Read32(call, &bytes) != 4) {
  	    warnx("rx_Read failed to read bytes");
  	    return -1;
  	}
***************
*** 446,452 ****
  	sendbytes(call, bytes);
  
  	data = htonl(RXPERF_MAGIC_COOKIE);
! 	if (rx_Write(call, &data, 4) != 4) {
  	    warnx("rx_Write failed when sending back result");
  	    return -1;
  	}
--- 452,458 ----
  	sendbytes(call, bytes);
  
  	data = htonl(RXPERF_MAGIC_COOKIE);
! 	if (rx_Write32(call, &data) != 4) {
  	    warnx("rx_Write failed when sending back result");
  	    return -1;
  	}
***************
*** 467,473 ****
   */
  
  static void
! do_server(int port)
  {
      struct rx_service *service;
      struct rx_securityClass *secureobj;
--- 473,479 ----
   */
  
  static void
! do_server(int port, int nojumbo, int maxmtu)
  {
      struct rx_service *service;
      struct rx_securityClass *secureobj;
***************
*** 478,483 ****
--- 484,493 ----
      if (ret)
  	errx(1, "rx_Init failed");
  
+     if (nojumbo)
+       rx_SetNoJumbo();
+     if (maxmtu)
+       rx_SetMaxMTU(maxmtu);
      get_sec(1, &secureobj, &secureindex);
  
      service =
***************
*** 547,553 ****
  
  static void
  do_client(const char *server, int port, char *filename, int32_t command,
! 	  int32_t times, int32_t bytes, int32_t sendtimes, int32_t recvtimes)
  {
      struct rx_connection *conn;
      struct rx_call *call;
--- 557,564 ----
  
  static void
  do_client(const char *server, int port, char *filename, int32_t command,
! 	  int32_t times, int32_t bytes, int32_t sendtimes, int32_t recvtimes,
!           int dumpstats, int nojumbo, int maxmtu)
  {
      struct rx_connection *conn;
      struct rx_call *call;
***************
*** 568,573 ****
--- 579,588 ----
      if (ret)
  	errx(1, "rx_Init failed");
  
+     if (nojumbo)
+       rx_SetNoJumbo();
+     if (maxmtu)
+       rx_SetMaxMTU(maxmtu);
      get_sec(0, &secureobj, &secureindex);
  
      conn = rx_NewConnection(addr, port, RX_SERVER_ID, secureobj, secureindex);
***************
*** 587,605 ****
  	    errx(1, "rx_NewCall failed");
  
  	data = htonl(RX_PERF_VERSION);
! 	if (rx_Write(call, &data, 4) != 4)
! 	    errx(1, "rx_Write failed to send version");
  
  	data = htonl(command);
! 	if (rx_Write(call, &data, 4) != 4)
! 	    errx(1, "rx_Write failed to send command");
  
  	data = htonl(rxread_size);
! 	if (rx_Write(call, &data, 4) != 4)
! 	    errx(1, "rx_Write failed to send read size");
  	data = htonl(rxwrite_size);
! 	if (rx_Write(call, &data, 4) != 4)
! 	    errx(1, "rx_Write failed to send write read");
  
  
  	switch (command) {
--- 602,620 ----
  	    errx(1, "rx_NewCall failed");
  
  	data = htonl(RX_PERF_VERSION);
! 	if (rx_Write32(call, &data) != 4)
! 	    errx(1, "rx_Write failed to send version (err %d)", rx_Error(call));
  
  	data = htonl(command);
! 	if (rx_Write32(call, &data) != 4)
! 	    errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
  
  	data = htonl(rxread_size);
! 	if (rx_Write32(call, &data) != 4)
! 	    errx(1, "rx_Write failed to send read size (err %d)", rx_Error(call));
  	data = htonl(rxwrite_size);
! 	if (rx_Write32(call, &data) != 4)
! 	    errx(1, "rx_Write failed to send write read (err %d)", rx_Error(call));
  
  
  	switch (command) {
***************
*** 607,621 ****
  	    DBFPRINT(("command "));
  
  	    data = htonl(bytes);
! 	    if (rx_Write(call, &data, 4) != 4)
! 		errx(1, "rx_Write failed to send size");
  
  	    DBFPRINT(("sending(%d) ", bytes));
  	    if (readbytes(call, bytes))
! 		errx(1, "sendbytes");
  
! 	    if (rx_Read(call, &data, 4) != 4)
! 		errx(1, "failed to read result from server");
  
  	    if (data != htonl(RXPERF_MAGIC_COOKIE))
  		warn("server send wrong magic cookie in responce");
--- 622,636 ----
  	    DBFPRINT(("command "));
  
  	    data = htonl(bytes);
! 	    if (rx_Write32(call, &data) != 4)
! 		errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
  
  	    DBFPRINT(("sending(%d) ", bytes));
  	    if (readbytes(call, bytes))
! 		errx(1, "sendbytes (err %d)", rx_Error(call));
  
! 	    if (rx_Read32(call, &data) != 4)
! 		errx(1, "failed to read result from server (err %d)", rx_Error(call));
  
  	    if (data != htonl(RXPERF_MAGIC_COOKIE))
  		warn("server send wrong magic cookie in responce");
***************
*** 627,641 ****
  	    DBFPRINT(("command "));
  
  	    data = htonl(bytes);
! 	    if (rx_Write(call, &data, 4) != 4)
! 		errx(1, "rx_Write failed to send size");
  
  	    DBFPRINT(("sending(%d) ", bytes));
  	    if (sendbytes(call, bytes))
! 		errx(1, "sendbytes");
  
! 	    if (rx_Read(call, &data, 4) != 4)
! 		errx(1, "failed to read result from server");
  
  	    if (data != htonl(RXPERF_MAGIC_COOKIE))
  		warn("server send wrong magic cookie in responce");
--- 642,656 ----
  	    DBFPRINT(("command "));
  
  	    data = htonl(bytes);
! 	    if (rx_Write32(call, &data) != 4)
! 		errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
  
  	    DBFPRINT(("sending(%d) ", bytes));
  	    if (sendbytes(call, bytes))
! 		errx(1, "sendbytes (err %d)", rx_Error(call));
  
! 	    if (rx_Read32(call, &data) != 4)
! 		errx(1, "failed to read result from server (err %d)", rx_Error(call));
  
  	    if (data != htonl(RXPERF_MAGIC_COOKIE))
  		warn("server send wrong magic cookie in responce");
***************
*** 647,667 ****
  	    DBFPRINT(("commands "));
  
  	    data = htonl(sendtimes);
! 	    if (rx_Write(call, &data, 4) != 4)
! 		errx(1, "rx_Write failed to send command");
  
  	    data = htonl(recvtimes);
! 	    if (rx_Write(call, &data, 4) != 4)
! 		errx(1, "rx_Write failed to send command");
  
  	    DBFPRINT(("send(%d) ", sendtimes));
! 	    sendbytes(call, sendtimes);
  
  	    DBFPRINT(("recv(%d) ", recvtimes));
! 	    readbytes(call, recvtimes);
  
! 	    if (rx_Read(call, &bytes, 4) != 4)
! 		errx(1, "failed to read result from server");
  
  	    if (bytes != htonl(RXPERF_MAGIC_COOKIE))
  		warn("server send wrong magic cookie in responce");
--- 662,684 ----
  	    DBFPRINT(("commands "));
  
  	    data = htonl(sendtimes);
! 	    if (rx_Write32(call, &data) != 4)
! 		errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
  
  	    data = htonl(recvtimes);
! 	    if (rx_Write32(call, &data) != 4)
! 		errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
  
  	    DBFPRINT(("send(%d) ", sendtimes));
! 	    if (sendbytes(call, sendtimes))
! 		errx(1, "sendbytes (err %d)", rx_Error(call));
  
  	    DBFPRINT(("recv(%d) ", recvtimes));
! 	    if (readbytes(call, recvtimes))
! 		errx(1, "sendbytes (err %d)", rx_Error(call));
  
! 	    if (rx_Read32(call, &bytes) != 4)
! 		errx(1, "failed to read result from server (err %d)", rx_Error(call));
  
  	    if (bytes != htonl(RXPERF_MAGIC_COOKIE))
  		warn("server send wrong magic cookie in responce");
***************
*** 673,684 ****
  	    readfile(filename, &readwrite, &num);
  
  	    data = htonl(num);
! 	    if (rx_Write(call, &data, sizeof(data)) != 4)
! 		errx(1, "rx_Write failed to send size");
  
  	    if (rx_Write(call, readwrite, num * sizeof(u_int32_t))
  		!= num * sizeof(u_int32_t))
! 		errx(1, "rx_Write failed to send list");
  
  	    for (i = 0; i < num; i++) {
  		if (readwrite[i] == 0)
--- 690,701 ----
  	    readfile(filename, &readwrite, &num);
  
  	    data = htonl(num);
! 	    if (rx_Write32(call, &data) != 4)
! 		errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
  
  	    if (rx_Write(call, readwrite, num * sizeof(u_int32_t))
  		!= num * sizeof(u_int32_t))
! 		errx(1, "rx_Write failed to send list (err %d)", rx_Error(call));
  
  	    for (i = 0; i < num; i++) {
  		if (readwrite[i] == 0)
***************
*** 687,696 ****
  		size = ntohl(readwrite[i]) * sizeof(u_int32_t);
  
  		if (readp) {
! 		    readbytes(call, size);
  		    DBFPRINT(("read\n"));
  		} else {
! 		    sendbytes(call, size);
  		    DBFPRINT(("send\n"));
  		}
  	    }
--- 704,715 ----
  		size = ntohl(readwrite[i]) * sizeof(u_int32_t);
  
  		if (readp) {
! 		    if (readbytes(call, size))
! 			errx(1, "sendbytes (err %d)", rx_Error(call));
  		    DBFPRINT(("read\n"));
  		} else {
! 		    if (sendbytes(call, size))
! 			errx(1, "sendbytes (err %d)", rx_Error(call));
  		    DBFPRINT(("send\n"));
  		}
  	    }
***************
*** 705,710 ****
--- 724,733 ----
      end_and_print_timer(stamp);
      DBFPRINT(("done for good\n"));
  
+     if (dumpstats) {
+ 	rx_PrintStats(stdout);
+ 	rx_PrintPeerStats(stdout, conn->peer);
+     }
      rx_Finalize();
  }
  
***************
*** 721,727 ****
      fprintf(stderr, "usage: %s client -c file -f filename\n", __progname);
      fprintf(stderr,
  	    "%s: usage:	common option to the client "
! 	    "-w <write-bytes> -r <read-bytes> -T times -p port -s server\n",
  	    __progname);
      fprintf(stderr, "usage: %s server -p port\n", __progname);
  #undef COMMMON
--- 744,750 ----
      fprintf(stderr, "usage: %s client -c file -f filename\n", __progname);
      fprintf(stderr,
  	    "%s: usage:	common option to the client "
! 	    "-w <write-bytes> -r <read-bytes> -T times -p port -s server -D\n",
  	    __progname);
      fprintf(stderr, "usage: %s server -p port\n", __progname);
  #undef COMMMON
***************
*** 736,745 ****
  rxperf_server(int argc, char **argv)
  {
      int port = DEFAULT_PORT;
      char *ptr;
      int ch;
  
!     while ((ch = getopt(argc, argv, "r:d:p:w:")) != -1) {
  	switch (ch) {
  	case 'd':
  #ifdef RXDEBUG
--- 759,770 ----
  rxperf_server(int argc, char **argv)
  {
      int port = DEFAULT_PORT;
+     int nojumbo = 0;
+     int maxmtu = 0;
      char *ptr;
      int ch;
  
!     while ((ch = getopt(argc, argv, "r:d:p:w:jm:4")) != -1) {
  	switch (ch) {
  	case 'd':
  #ifdef RXDEBUG
***************
*** 771,776 ****
--- 796,812 ----
  		errx(1, "%d > sizeof(somebuf) (%d)", rxwrite_size,
  		     sizeof(somebuf));
  	    break;
+ 	case 'j':
+ 	  nojumbo=1;
+ 	  break;
+ 	case 'm':
+ 	  maxmtu = strtol(optarg, &ptr, 0);
+ 	  if (ptr && *ptr != '\0')
+ 	    errx(1, "can't resolve rx maxmtu to use");
+ 	    break;
+ 	case '4':
+ 	  RX_IPUDP_SIZE = 28;
+ 	  break;
  	default:
  	    usage();
  	}
***************
*** 779,785 ****
      if (optind != argc)
  	usage();
  
!     do_server(htons(port));
  
      return 0;
  }
--- 815,821 ----
      if (optind != argc)
  	usage();
  
!     do_server(htons(port), nojumbo, maxmtu);
  
      return 0;
  }
***************
*** 799,810 ****
      int sendtimes = 3;
      int recvtimes = 30;
      int times = 100;
      char *ptr;
      int ch;
  
      cmd = RX_PERF_UNKNOWN;
  
!     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:r:s:w:f:")) != -1) {
  	switch (ch) {
  	case 'b':
  	    bytes = strtol(optarg, &ptr, 0);
--- 835,849 ----
      int sendtimes = 3;
      int recvtimes = 30;
      int times = 100;
+     int dumpstats = 0;
+     int nojumbo = 0;
+     int maxmtu = 0;
      char *ptr;
      int ch;
  
      cmd = RX_PERF_UNKNOWN;
  
!     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:r:s:w:f:Djm:4")) != -1) {
  	switch (ch) {
  	case 'b':
  	    bytes = strtol(optarg, &ptr, 0);
***************
*** 876,881 ****
--- 915,938 ----
  	case 'f':
  	    filename = optarg;
  	    break;
+ 	case 'D':
+ #ifdef RXDEBUG
+ 	    dumpstats = 1;
+ #else
+ 	    errx(1, "compiled without RXDEBUG");
+ #endif
+ 	    break;
+ 	case 'j':
+ 	  nojumbo=1;
+ 	  break;
+ 	case 'm':
+ 	  maxmtu = strtol(optarg, &ptr, 0);
+ 	  if (ptr && *ptr != '\0')
+ 	    errx(1, "can't resolve rx maxmtu to use");
+ 	    break;
+ 	case '4':
+ 	  RX_IPUDP_SIZE = 28;
+ 	  break;
  	default:
  	    usage();
  	}
***************
*** 888,894 ****
  	errx(1, "no command given to the client");
  
      do_client(host, htons(port), filename, cmd, times, bytes, sendtimes,
! 	      recvtimes);
  
      return 0;
  }
--- 945,951 ----
  	errx(1, "no command given to the client");
  
      do_client(host, htons(port), filename, cmd, times, bytes, sendtimes,
! 	      recvtimes, dumpstats, nojumbo, maxmtu);
  
      return 0;
  }
Index: openafs/src/rx/LINUX/rx_knet.c
diff -c openafs/src/rx/LINUX/rx_knet.c:1.32.2.6 openafs/src/rx/LINUX/rx_knet.c:1.32.2.6.2.1
*** openafs/src/rx/LINUX/rx_knet.c:1.32.2.6	Wed Jan 30 12:26:05 2008
--- openafs/src/rx/LINUX/rx_knet.c	Tue May 20 17:59:44 2008
***************
*** 16,22 ****
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/LINUX/rx_knet.c,v 1.32.2.6 2008/01/30 17:26:05 shadow Exp $");
  
  #include <linux/version.h>
  #ifdef AFS_LINUX22_ENV
--- 16,22 ----
  #include "afs/param.h"
  
  RCSID
!     ("$Header: /cvs/openafs/src/rx/LINUX/rx_knet.c,v 1.32.2.6.2.1 2008/05/20 21:59:44 shadow Exp $");
  
  #include <linux/version.h>
  #ifdef AFS_LINUX22_ENV
***************
*** 25,30 ****
--- 25,34 ----
  #include "h/smp_lock.h"
  #endif
  #include <asm/uaccess.h>
+ #ifdef ADAPT_PMTU
+ #include <linux/errqueue.h>
+ #include <linux/icmp.h>
+ #endif
  
  /* rxk_NewSocket
   * open and bind RX socket
***************
*** 36,43 ****
      struct sockaddr_in myaddr;
      int code;
      KERNEL_SPACE_DECL;
      int pmtu = IP_PMTUDISC_DONT;
! 
  
      /* We need a better test for this. if you need it back, tell us
       * how to detect it. 
--- 40,51 ----
      struct sockaddr_in myaddr;
      int code;
      KERNEL_SPACE_DECL;
+ #ifdef ADAPT_PMTU
+     int pmtu = IP_PMTUDISC_WANT;
+     int do_recverr = 1;
+ #else
      int pmtu = IP_PMTUDISC_DONT;
! #endif
  
      /* We need a better test for this. if you need it back, tell us
       * how to detect it. 
***************
*** 69,74 ****
--- 77,86 ----
      TO_USER_SPACE();
      sockp->ops->setsockopt(sockp, SOL_IP, IP_MTU_DISCOVER, (char *)&pmtu,
                             sizeof(pmtu));
+ #ifdef ADAPT_PMTU
+     sockp->ops->setsockopt(sockp, SOL_IP, IP_RECVERR, (char *)&do_recverr,
+                            sizeof(do_recverr));
+ #endif
      TO_KERNEL_SPACE();
      return (osi_socket *)sockp;
  }
***************
*** 87,92 ****
--- 99,163 ----
      return 0;
  }
  
+ #ifdef ADAPT_PMTU
+ void
+ handle_socket_error(osi_socket so)
+ {
+     KERNEL_SPACE_DECL;
+     struct msghdr msg;
+     struct cmsghdr *cmsg;
+     struct sock_extended_err *err;
+     struct sockaddr_in addr;
+     struct sockaddr *offender;
+     char *controlmsgbuf;
+     int code;
+     struct socket *sop = (struct socket *)so;
+ 
+     if (!(controlmsgbuf=rxi_Alloc(256)))
+ 	return;
+     msg.msg_name = &addr;
+     msg.msg_namelen = sizeof(addr);
+     msg.msg_iov = NULL;
+     msg.msg_iovlen = 0;
+     msg.msg_control = controlmsgbuf;
+     msg.msg_controllen = 256;
+     msg.msg_flags = 0;
+ 
+     TO_USER_SPACE();
+     code = sock_recvmsg(sop, &msg, 256, MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC);
+     TO_KERNEL_SPACE();
+ 
+     if (code < 0 || !(msg.msg_flags & MSG_ERRQUEUE))
+ 	goto out;
+ 
+     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ 	if (CMSG_OK(&msg, cmsg) && cmsg->cmsg_level == SOL_IP &&
+ 	    cmsg->cmsg_type == IP_RECVERR)
+ 	    break;
+     }
+     if (!cmsg)
+ 	goto out;
+     err = CMSG_DATA(cmsg);
+     offender = SO_EE_OFFENDER(err);
+     
+     if (offender->sa_family != AF_INET)
+        goto out;
+ 
+     memcpy(&addr, offender, sizeof(addr));
+ 
+     if (err->ee_origin == SO_EE_ORIGIN_ICMP &&
+ 	err->ee_type == ICMP_DEST_UNREACH &&
+ 	err->ee_code == ICMP_FRAG_NEEDED) {
+ 	rxi_SetPeerMtu(ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port),
+ 		       err->ee_info);
+     }
+     /* other DEST_UNREACH's and TIME_EXCEEDED should be dealt with too */
+ 
+ out:
+     rxi_Free(controlmsgbuf, 256);
+     return;
+ }
+ #endif
  
  /* osi_NetSend
   *
***************
*** 100,106 ****
  {
      KERNEL_SPACE_DECL;
      struct msghdr msg;
!     int code;
  
      msg.msg_iovlen = iovcnt;
      msg.msg_iov = iovec;
--- 171,192 ----
  {
      KERNEL_SPACE_DECL;
      struct msghdr msg;
!     int code, sockerr;
!     size_t esize;
! 
! #ifdef ADAPT_PMTU
!     while (1) {
! 	sockerr=0;
! 	esize = sizeof(sockerr);
! 	TO_USER_SPACE();
! 	sop->ops->getsockopt(sop, SOL_SOCKET, SO_ERROR, (char *)&sockerr,
! 			   &esize);
! 	TO_KERNEL_SPACE();
! 	if (sockerr == 0)
! 	   break;
! 	handle_socket_error(sop);
!     }
! #endif
  
      msg.msg_iovlen = iovcnt;
      msg.msg_iov = iovec;
***************
*** 144,156 ****
  {
      KERNEL_SPACE_DECL;
      struct msghdr msg;
!     int code;
      struct iovec tmpvec[RX_MAXWVECS + 2];
      struct socket *sop = (struct socket *)so;
  
      if (iovcnt > RX_MAXWVECS + 2) {
  	osi_Panic("Too many (%d) iovecs passed to osi_NetReceive\n", iovcnt);
      }
      memcpy(tmpvec, iov, iovcnt * sizeof(struct iovec));
      msg.msg_name = from;
      msg.msg_iov = tmpvec;
--- 230,256 ----
  {
      KERNEL_SPACE_DECL;
      struct msghdr msg;
!     int code, sockerr;
!     size_t esize;
      struct iovec tmpvec[RX_MAXWVECS + 2];
      struct socket *sop = (struct socket *)so;
  
      if (iovcnt > RX_MAXWVECS + 2) {
  	osi_Panic("Too many (%d) iovecs passed to osi_NetReceive\n", iovcnt);
      }
+ #ifdef ADAPT_PMTU
+     while (1) {
+ 	sockerr=0;
+ 	esize = sizeof(sockerr);
+  	TO_USER_SPACE();
+ 	sop->ops->getsockopt(sop, SOL_SOCKET, SO_ERROR, (char *)&sockerr,
+ 			   &esize);
+ 	TO_KERNEL_SPACE();
+ 	if (sockerr == 0)
+ 	   break;
+ 	handle_socket_error(so);
+     }
+ #endif
      memcpy(tmpvec, iov, iovcnt * sizeof(struct iovec));
      msg.msg_name = from;
      msg.msg_iov = tmpvec;
Index: openafs/src/venus/fs.c
diff -c openafs/src/venus/fs.c:1.30.2.13 openafs/src/venus/fs.c:1.30.2.13.2.2
*** openafs/src/venus/fs.c:1.30.2.13	Mon Nov 26 16:08:45 2007
--- openafs/src/venus/fs.c	Tue May 20 18:22:04 2008
***************
*** 11,17 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/venus/fs.c,v 1.30.2.13 2007/11/26 21:08:45 shadow Exp $");
  
  #include <afs/afs_args.h>
  #include <rx/xdr.h>
--- 11,17 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/venus/fs.c,v 1.30.2.13.2.2 2008/05/20 22:22:04 shadow Exp $");
  
  #include <afs/afs_args.h>
  #include <rx/xdr.h>
***************
*** 1996,2001 ****
--- 1996,2034 ----
  }
  
  static int
+ PreCacheCmd(struct cmd_syndesc *as, char *arock)
+ {
+     afs_int32 code;
+     struct ViceIoctl blob;
+     afs_int32 temp;
+     
+     if (!as->parms[0].items && !as->parms[1].items) {
+ 	fprintf(stderr, "%s: syntax error in precache cmd.\n", pn);
+ 	return 1;
+     }
+     if (as->parms[0].items) {
+ 	code = util_GetInt32(as->parms[0].items->data, &temp);
+ 	if (code) {
+ 	    fprintf(stderr, "%s: bad integer specified for precache size.\n",
+ 		    pn);
+ 	    return 1;
+ 	}
+     } else
+ 	temp = 0;
+     blob.in = (char *)&temp;
+     blob.in_size = sizeof(afs_int32);
+     blob.out_size = 0;
+     code = pioctl(0, VIOCPRECACHE, &blob, 1);
+     if (code) {
+ 	Die(errno, NULL);
+ 	return 1;
+     }
+     
+     printf("New precache size set.\n");
+     return 0;
+ }
+ 
+ static int
  SetCacheSizeCmd(struct cmd_syndesc *as, void *arock)
  {
      afs_int32 code;
***************
*** 3654,3659 ****
--- 3687,3697 ----
      ts = cmd_CreateSyntax("uuid", UuidCmd, NULL, "manage the UUID for the cache manager");
      cmd_AddParm(ts, "-generate", CMD_FLAG, CMD_REQUIRED, "generate a new UUID");
  
+     ts = cmd_CreateSyntax("precache", PreCacheCmd, 0,
+ 			  "set precache size");
+     cmd_AddParm(ts, "-blocks", CMD_SINGLE, CMD_OPTIONAL,
+ 		"size in 1K byte blocks (0 => disable)");
+ 
      code = cmd_Dispatch(argc, argv);
      if (rxInitDone)
  	rx_Finalize();
Index: openafs/src/viced/viced.c
diff -c openafs/src/viced/viced.c:1.75.2.22 openafs/src/viced/viced.c:1.75.2.22.2.1
*** openafs/src/viced/viced.c:1.75.2.22	Tue May  6 11:03:07 2008
--- openafs/src/viced/viced.c	Tue May 20 15:33:24 2008
***************
*** 22,28 ****
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/viced.c,v 1.75.2.22 2008/05/06 15:03:07 shadow Exp $");
  
  #include <stdio.h>
  #include <stdlib.h>
--- 22,28 ----
  #include <afs/param.h>
  
  RCSID
!     ("$Header: /cvs/openafs/src/viced/viced.c,v 1.75.2.22.2.1 2008/05/20 19:33:24 shadow Exp $");
  
  #include <stdio.h>
  #include <stdlib.h>
***************
*** 2097,2102 ****
--- 2097,2103 ----
      rx_SetMinProcs(tservice, 3);
      rx_SetMaxProcs(tservice, lwps);
      rx_SetCheckReach(tservice, 1);
+     rx_SetServerIdleDeadErr(tservice, VNOSERVICE);
  
      tservice =
  	rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", sc, 4,
