[OpenAFS-port-freebsd] It starts and it stops!

Garrett Wollman wollman@khavrinen.lcs.mit.edu
Mon, 29 Sep 2003 00:30:34 -0400 (EDT)


I've finally gotten to the point where I can actually shut down the
client on FreeBSD-current without panicking.  I've also made a few
(incomplete) changes to the MI code to support linking without
libcompat (which is usually a bad idea).  (The code that I changed
should probably be refactored.)

As always, the patch is at <http://lcs.mit.edu/~wollman/openafs-fbsd52.patch>.
This time it's relative to top-of-tree.  For ease of commentary, I'm
also including it here.  The next steps would be:

- Make sure authentication works.  (Need to compile aklog for that....)
- Check all of the VNOPS with DEBUG_VFS_LOCKS to make certain that the
  locking protocol is being obeyed.
- Figure out the internal API for PAG stuff and make it do the Right
  Thing using MAC labels.
- VM system stress test (probably `make buildworld' with sources on
  AFS).
- Make sure 64-bit client ops work correctly.
- Fix compilation and test on 4.x.
- Fix compilation and test on other architectures.

? src/config/param.i386_fbsd_52.h
(To construct this file, do the obvious thing.)

Index: src/afs/afs.h
===================================================================
RCS file: /cvs/openafs/src/afs/afs.h,v
retrieving revision 1.42
diff -u -r1.42 afs.h
--- src/afs/afs.h	29 Aug 2003 22:00:04 -0000	1.42
+++ src/afs/afs.h	29 Sep 2003 03:45:27 -0000
@@ -545,15 +545,11 @@
 #define VPageCleaning 0x2	/* Solaris - Cache Trunc Daemon sez keep out */
 
 #define	CPSIZE	    2
-#if defined(AFS_FBSD_ENV)
-#define vrefCount   v.v_usecount
-#else
-#if defined(AFS_OBSD_ENV)
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
 #define vrefCount   v->v_usecount
 #else
 #define vrefCount   v.v_count
-#endif /* AFS_OBSD_ENV */
-#endif /* AFS_FBSD_ENV */
+#endif /* AFS_[OF]BSD_ENV */
 
 #ifdef AFS_LINUX24_ENV
 #define VREFCOUNT(v)		atomic_read(&((vnode_t *) v)->v_count)
@@ -598,7 +594,7 @@
 extern afs_uint32 afs_stampValue;	/* stamp for pair's usage */
 #define	MakeStamp()	(++afs_stampValue)
 
-#if defined(AFS_OBSD_ENV)
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
 #define VTOAFS(v) ((struct vcache *)(v)->v_data)
 #define AFSTOV(vc) ((vc)->v)
 #else
@@ -616,7 +612,7 @@
  * !(avc->nextfree) && !avc->vlruq.next => (FreeVCList == avc->nextfree)
  */
 struct vcache {
-#if defined(AFS_OBSD_ENV)
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
     struct vnode *v;
 #else
     struct vnode v;		/* Has reference count in v.v_count */
Index: src/afs/afs_call.c
===================================================================
RCS file: /cvs/openafs/src/afs/afs_call.c,v
retrieving revision 1.62
diff -u -r1.62 afs_call.c
--- src/afs/afs_call.c	8 Aug 2003 21:54:34 -0000	1.62
+++ src/afs/afs_call.c	29 Sep 2003 03:45:29 -0000
@@ -64,13 +64,12 @@
 struct lock__bsd__ afs_global_lock;
 #endif
 
-#if defined(AFS_XBSD_ENV)
+#if defined(AFS_XBSD_ENV) && !defined(AFS_FBSD50_ENV)
 struct lock afs_global_lock;
-#ifdef AFS_FBSD50_ENV
-struct thread *afs_global_owner;
-#else
 struct proc *afs_global_owner;
 #endif
+#ifdef AFS_FBSD50_ENV
+struct mtx afs_global_mtx;
 #endif
 
 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
Index: src/afs/afs_init.c
===================================================================
RCS file: /cvs/openafs/src/afs/afs_init.c,v
retrieving revision 1.26
diff -u -r1.26 afs_init.c
--- src/afs/afs_init.c	15 Jul 2003 23:14:12 -0000	1.26
+++ src/afs/afs_init.c	29 Sep 2003 03:45:30 -0000
@@ -41,7 +41,7 @@
 int afs_sysnamecount = 0;
 struct volume *Initialafs_freeVolList;
 int afs_memvolumes = 0;
-#ifdef AFS_OBSD_ENV
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
 static struct vnode *volumeVnode;
 #endif
 
@@ -295,7 +295,7 @@
     struct osi_file *tfile;
 
     AFS_STATCNT(afs_InitVolumeInfo);
-#if defined(AFS_OBSD_ENV)
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
     /*
      * On Open/NetBSD, we can get into big trouble if we don't hold the volume file
      * vnode.  SetupVolume holds afs_xvolume lock exclusive.
@@ -428,19 +428,24 @@
     cacheInode = filevp->i_ino;
     afs_cacheSBp = filevp->i_sb;
 #else
-#ifdef AFS_OBSD_ENV
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
     cacheInode = VTOI(filevp)->i_number;
     cacheDev.mp = filevp->v_mount;
     cacheDev.held_vnode = filevp;
+#ifdef AFS_OBSD_ENV
     AFS_HOLD(filevp);		/* Make sure mount point stays busy. XXX */
 #else
+    vref(filevp);
+    afs_cacheVfsp = filevp->v_vfsp;
+#endif
+#else
 #if defined(AFS_SGI62_ENV) || defined(AFS_HAVE_VXFS) || defined(AFS_DARWIN_ENV)
     afs_InitDualFSCacheOps(filevp);
 #endif
     cacheInode = afs_vnodeToInumber(filevp);
     cacheDev.dev = afs_vnodeToDev(filevp);
     afs_cacheVfsp = filevp->v_vfsp;
-#endif /* AFS_OBSD_ENV */
+#endif /* !AFS_[FO]BSD_ENV */
 #endif /* AFS_LINUX20_ENV */
     AFS_RELE(filevp);
 #endif /* AFS_LINUX22_ENV */
@@ -494,10 +499,12 @@
     RWLOCK_INIT(&afs_icl_lock, "afs_icl_lock");
     RWLOCK_INIT(&afs_xinterface, "afs_xinterface");
     LOCK_INIT(&afs_puttofileLock, "afs_puttofileLock");
+#ifndef AFS_FBSD_ENV
 #ifndef	AFS_AIX32_ENV
     LOCK_INIT(&osi_fsplock, "osi_fsplock");
 #endif
     LOCK_INIT(&osi_flplock, "osi_flplock");
+#endif
     RWLOCK_INIT(&afs_xconn, "afs_xconn");
 
     afs_CellInit();
@@ -669,11 +676,19 @@
 	afs_cacheFiles = afs_cacheBlocks = 0;
 	pag_epoch = maxIHint = nihints = usedihint = 0;
 	pagCounter = 0;
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
 #ifdef AFS_OBSD_ENV
 	AFS_RELE(volumeVnode);	/* let it go, finally. */
+#else
+	vrele(volumeVnode);
+#endif
 	volumeVnode = NULL;
 	if (cacheDev.held_vnode) {
+#ifdef AFS_OBSD_ENV
 	    AFS_RELE(cacheDev.held_vnode);
+#else
+	    vrele(cacheDev.held_vnode);
+#endif
 	    cacheDev.held_vnode = NULL;
 	}
 #endif
Index: src/afs/afs_osi.c
===================================================================
RCS file: /cvs/openafs/src/afs/afs_osi.c,v
retrieving revision 1.38
diff -u -r1.38 afs_osi.c
--- src/afs/afs_osi.c	27 Aug 2003 21:43:16 -0000	1.38
+++ src/afs/afs_osi.c	29 Sep 2003 03:45:31 -0000
@@ -57,6 +57,8 @@
 #elif defined(AFS_OSF_ENV)
     usimple_lock_init(&afs_global_lock);
     afs_global_owner = (thread_t) 0;
+#elif defined(AFS_FBSD50_ENV)
+    mtx_init(&afs_global_mtx, "AFS global lock", NULL, MTX_DEF);
 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     lockinit(&afs_global_lock, PLOCK, "afs global lock", 0, 0);
     afs_global_owner = 0;
@@ -433,6 +435,8 @@
     AFS_STATS(afs_stats_cmperf.OutStandingMemUsage += x);
 #ifdef AFS_LINUX20_ENV
     return osi_linux_alloc(x, 1);
+#elif defined(AFS_FBSD_ENV)
+    return osi_fbsd_alloc(x, 1);
 #else
     size = x;
     tm = (struct osimem *)AFS_KALLOC(size);
@@ -479,6 +483,8 @@
     AFS_STATS(afs_stats_cmperf.OutStandingMemUsage -= asize);
 #if defined(AFS_LINUX20_ENV)
     osi_linux_free(x);
+#elif defined(AFS_FBSD_ENV)
+    osi_fbsd_free(x);
 #else
     AFS_KFREE((struct osimem *)x, asize);
 #endif
Index: src/afs/afs_osi.h
===================================================================
RCS file: /cvs/openafs/src/afs/afs_osi.h,v
retrieving revision 1.19
diff -u -r1.19 afs_osi.h
--- src/afs/afs_osi.h	29 Aug 2003 22:00:04 -0000	1.19
+++ src/afs/afs_osi.h	29 Sep 2003 03:45:31 -0000
@@ -13,6 +13,10 @@
 #include "h/types.h"
 #include "h/param.h"
 
+#ifdef AFS_FBSD50_ENV
+#include <sys/condvar.h>
+#endif
+
 #ifdef AFS_LINUX20_ENV
 #ifndef _LINUX_CODA_FS_I
 #define _LINUX_CODA_FS_I
@@ -68,11 +72,13 @@
 };
 
 struct osi_dev {
-#ifdef AFS_OBSD_ENV
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
     struct mount *mp;
     struct vnode *held_vnode;
+/* see if we need this...
 #elif defined(AFS_FBSD50_ENV)
     struct cdev *dev;
+*/
 #elif defined(AFS_AIX42_ENV)
     dev_t dev;
 #else
@@ -81,7 +87,12 @@
 };
 
 struct afs_osi_WaitHandle {
+#ifdef AFS_FBSD50_ENV
+    struct cv wh_condvar;
+    int wh_inited;		/* XXX */
+#else
     caddr_t proc;		/* process waiting */
+#endif
 };
 
 #define	osi_SetFileProc(x,p)	((x)->proc=(p))
Index: src/afs/afs_osi_alloc.c
===================================================================
RCS file: /cvs/openafs/src/afs/afs_osi_alloc.c,v
retrieving revision 1.9
diff -u -r1.9 afs_osi_alloc.c
--- src/afs/afs_osi_alloc.c	15 Jul 2003 23:14:12 -0000	1.9
+++ src/afs/afs_osi_alloc.c	29 Sep 2003 03:45:31 -0000
@@ -19,6 +19,7 @@
 #include "afsincludes.h"	/* Afs-based standard headers */
 #include "afs/afs_stats.h"	/* afs statistics */
 
+#ifndef AFS_FBSD_ENV
 #ifdef AFS_AIX41_ENV
 #include "sys/lockl.h"
 #include "sys/sleep.h"
@@ -368,3 +369,4 @@
 	LOCK_INIT(&osi_flplock, "osi_flplock");
     }
 }
+#endif
Index: src/afs/afs_prototypes.h
===================================================================
RCS file: /cvs/openafs/src/afs/afs_prototypes.h,v
retrieving revision 1.42
diff -u -r1.42 afs_prototypes.h
--- src/afs/afs_prototypes.h	15 Jul 2003 23:14:12 -0000	1.42
+++ src/afs/afs_prototypes.h	29 Sep 2003 03:45:32 -0000
@@ -465,8 +465,12 @@
 extern void afs_osi_MaskSignals(void);
 extern void afs_osi_UnmaskRxkSignals(void);
 extern void *afs_osi_Alloc(size_t x);
+#ifndef afs_osi_Alloc_NoSleep
 extern void *afs_osi_Alloc_NoSleep(size_t x);
+#endif
+#ifndef afs_osi_Free
 extern void afs_osi_Free(void *x, size_t asize);
+#endif
 extern void afs_osi_FreeStr(char *x);
 extern void osi_Init(void);
 extern int osi_Active(register struct vcache *avc);
@@ -503,9 +507,11 @@
 extern afs_int32 PagInCred(const struct AFS_UCRED *cred);
 
 /* afs_osi_alloc.c */
+#ifndef AFS_FBSD_ENV
 extern afs_int32 afs_preallocs;
 extern afs_lock_t osi_fsplock;
 extern afs_lock_t osi_flplock;
+#endif
 extern void osi_FreeLargeSpace(void *adata);
 extern void osi_FreeMediumSpace(void *adata);
 extern void osi_FreeSmallSpace(void *adata);
Index: src/afs/afs_vcache.c
===================================================================
RCS file: /cvs/openafs/src/afs/afs_vcache.c,v
retrieving revision 1.55
diff -u -r1.55 afs_vcache.c
--- src/afs/afs_vcache.c	3 Sep 2003 16:47:15 -0000	1.55
+++ src/afs/afs_vcache.c	29 Sep 2003 03:45:35 -0000
@@ -153,7 +153,7 @@
 	afs_osi_Free(avc->linkData, strlen(avc->linkData) + 1);
 	avc->linkData = NULL;
     }
-#if defined(AFS_OBSD_ENV)
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
     /* OK, there are no internal vrefCounts, so there shouldn't
      * be any more refs here. */
     if (avc->v) {
@@ -801,36 +801,6 @@
 		    continue;	/* start over - may have raced. */
 		}
 	    }
-#elif defined(AFS_FBSD50_ENV)
-	    if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
-		&& (tvc->states & CUnlinkedDel) == 0) {
-		if (!(VOP_LOCK(&tvc->v, LK_EXCLUSIVE, curthread))) {
-		    if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
-			&& (tvc->states & CUnlinkedDel) == 0) {
-			VREFCOUNT_DEC(tvc);
-			AFS_GUNLOCK();	/* perhaps inline inactive for locking */
-			VOP_INACTIVE(&tvc->v, curthread);
-			AFS_GLOCK();
-		    } else {
-			VOP_UNLOCK(&tvc->v, 0, curthread);
-		    }
-		}
-	    }
-#elif defined(AFS_FBSD_ENV) && !defined(AFS_FBSD50_ENV)
-	    if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
-		&& (tvc->states & CUnlinkedDel) == 0) {
-		if (!(VOP_LOCK(&tvc->v, LK_EXCLUSIVE, curproc))) {
-		    if (VREFCOUNT(tvc) == 1 && tvc->opens == 0
-			&& (tvc->states & CUnlinkedDel) == 0) {
-			VREFCOUNT_DEC(tvc);
-			AFS_GUNLOCK();	/* perhaps inline inactive for locking */
-			VOP_INACTIVE(&tvc->v, curproc);
-			AFS_GLOCK();
-		    } else {
-			VOP_UNLOCK(&tvc->v, 0, curproc);
-		    }
-		}
-	    }
 #elif defined(AFS_LINUX22_ENV)
 	    if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0)
 		afs_TryFlushDcacheChildren(tvc);
@@ -838,12 +808,13 @@
 
 	    if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
 		&& (tvc->states & CUnlinkedDel) == 0) {
-#ifdef AFS_OBSD_ENV
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
 		/*
 		 * vgone() reclaims the vnode, which calls afs_FlushVCache(),
 		 * then it puts the vnode on the free list.
 		 * If we don't do this we end up with a cleaned vnode that's
 		 * not on the free list.
+		 * XXX assume FreeBSD is the same for now.
 		 */
 		vgone(AFSTOV(tvc));
 		code = fv_slept = 0;
@@ -907,7 +878,7 @@
     vm_info_ptr = tvc->v.v_vm_info;
 #endif /* AFS_MACH_ENV */
 
-#if defined(AFS_OBSD_ENV)
+#if defined(AFS_OBSD_ENV) || defined(AFS_FBSD_ENV)
     if (tvc->v)
 	panic("afs_NewVCache(): free vcache with vnode attached");
 #endif
@@ -931,6 +902,32 @@
     afs_nbsd_getnewvnode(tvc);	/* includes one refcount */
     lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
 #endif
+#ifdef AFS_FBSD_ENV
+    {
+	struct vnode *vp;
+
+	AFS_GUNLOCK();
+	if (getnewvnode("afs", afs_globalVFS, afs_vnodeop_p, &vp))
+	    panic("afs getnewvnode");	/* can't happen */
+	AFS_GLOCK();
+	if (tvc->v != NULL) {
+	    /* I'd like to know if this ever happens...
+	       We don't drop global for the rest of this function,
+	       so if we do lose the race, the other thread should
+	       have found the same vnode and finished initializing
+	       the vcache entry.  Is it conceivable that this vcache
+	       entry could be recycled during this interval?  If so,
+	       then there probably needs to be some sort of additional
+	       mutual exclusion (an Embryonic flag would suffice).
+		-GAW */
+	    printf("afs_NewVCache: lost the race\n");
+	    return (tvc);
+	}
+	tvc->v = vp;
+	tvc->v->v_data = tvc;
+	lockinit(&tvc->rwlock, PINOD, "vcache", 0, 0);
+    }
+#endif
     tvc->parentVnode = 0;
     tvc->mvid = NULL;
     tvc->linkData = NULL;
@@ -955,9 +952,9 @@
     /* Hold it for the LRU (should make count 2) */
     VN_HOLD(AFSTOV(tvc));
 #else /* AFS_OSF_ENV */
-#ifndef AFS_OBSD_ENV
+#if !defined(AFS_OBSD_ENV) && !defined(AFS_FBSD_ENV)
     VREFCOUNT_SET(tvc, 1);	/* us */
-#endif /* AFS_OBSD_ENV */
+#endif /* AFS_[FO]BSD_ENV */
 #endif /* AFS_OSF_ENV */
 #ifdef	AFS_AIX32_ENV
     LOCK_INIT(&tvc->pvmlock, "vcache pvmlock");
@@ -1038,14 +1035,6 @@
     tvc->v.v_freelist.tqe_prev = (struct vnode **)0xdeadb;
     /*tvc->vrefCount++; */
 #endif
-#ifdef AFS_FBSD_ENV
-    lockinit(&tvc->rwlock, PINOD, "vcache rwlock", 0, 0);
-    cache_purge(AFSTOV(tvc));
-    tvc->v.v_data = tvc;
-    tvc->v.v_tag = VT_AFS;
-    tvc->v.v_usecount++;	/* steal an extra ref for now so vfree never happens */
-    /* This extra ref is dealt with above... */
-#endif
     /*
      * The proper value for mvstat (for root fids) is setup by the caller.
      */
@@ -1798,6 +1787,11 @@
     VOP_LOCK(AFSTOV(tvc), LK_EXCLUSIVE | LK_RETRY, curproc);
     uvm_vnp_uncache(AFSTOV(tvc));
     VOP_UNLOCK(AFSTOV(tvc), 0, curproc);
+#endif
+#ifdef AFS_FBSD_ENV
+    vn_lock(AFSTOV(tvc), LK_EXCLUSIVE | LK_RETRY, curthread);
+    vinvalbuf(AFSTOV(tvc), V_SAVE, curthread->td_ucred, curthread, PINOD, 0);
+    VOP_UNLOCK(AFSTOV(tvc), LK_EXCLUSIVE, curthread);
 #endif
 
     ObtainWriteLock(&afs_xcbhash, 464);
Index: src/afs/FBSD/osi_file.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_file.c,v
retrieving revision 1.12
diff -u -r1.12 osi_file.c
--- src/afs/FBSD/osi_file.c	9 Sep 2003 21:14:34 -0000	1.12
+++ src/afs/FBSD/osi_file.c	29 Sep 2003 03:45:35 -0000
@@ -73,7 +73,9 @@
     MObtainWriteLock(&afs_xosi, 320);
     AFS_GUNLOCK();
 #if defined(AFS_FBSD50_ENV)
+    vn_lock(afile->vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
     code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
+    VOP_UNLOCK(afile->vnode, LK_EXCLUSIVE, curthread);
 #else
     code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curproc);
 #endif
Index: src/afs/FBSD/osi_machdep.h
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_machdep.h,v
retrieving revision 1.7
diff -u -r1.7 osi_machdep.h
--- src/afs/FBSD/osi_machdep.h	15 Jul 2003 23:14:19 -0000	1.7
+++ src/afs/FBSD/osi_machdep.h	29 Sep 2003 03:45:35 -0000
@@ -21,6 +21,7 @@
 
 #include <sys/lock.h>
 #include <sys/time.h>
+#include <sys/mutex.h>
 /* #include <kern/sched_prim.h> */
 /* #include <sys/unix_defs.h> */
 
@@ -42,7 +43,13 @@
 #define iodone biodone
 #endif
 
-#define osi_vnhold(avc,r) do { VN_HOLD((struct vnode *)(avc)); } while (0)
+#define osi_vnhold(avc,r)	vref(AFSTOV(avc))
+#undef vSetVfsp
+#define vSetVfsp(vc, vfsp)	AFSTOV(vc)->v_mount = (vfsp)
+#undef vSetType
+#define vSetType(vc, type)	AFSTOV(vc)->v_type = (type)
+#undef vType
+#define	vType(vc)		AFSTOV(vc)->v_type
 
 #undef gop_lookupname
 #define gop_lookupname osi_lookupname
@@ -52,7 +59,9 @@
 #define afs_strcat(s1, s2)	strcat((s1), (s2))
 
 #ifdef KERNEL
-extern struct lock afs_global_lock;
+
+#undef afs_osi_Alloc_NoSleep
+#define afs_osi_Alloc_NoSleep(size) osi_fbsd_alloc((size), 0)
 
 #if defined(AFS_FBSD50_ENV)
 #define VT_AFS		"afs"
@@ -64,24 +73,13 @@
 #define simple_unlock(x) mtx_unlock(x)
 #define        gop_rdwr(rw,gp,base,len,offset,segflg,unit,cred,aresid) \
   vn_rdwr((rw),(gp),(base),(len),(offset),(segflg),(unit),(cred),(cred),(aresid), curthread)
-extern struct thread *afs_global_owner;
-#define AFS_GLOCK() \
-    do { \
-        osi_Assert(curthread); \
- 	lockmgr(&afs_global_lock, LK_EXCLUSIVE, 0, curthread); \
-        osi_Assert(afs_global_owner == 0); \
-   	afs_global_owner = curthread; \
-    } while (0)
-#define AFS_GUNLOCK() \
-    do { \
-        osi_Assert(curthread); \
- 	osi_Assert(afs_global_owner == curthread); \
-        afs_global_owner = 0; \
-        lockmgr(&afs_global_lock, LK_RELEASE, 0, curthread); \
-    } while(0)
-#define ISAFS_GLOCK() (afs_global_owner == curthread && curthread)
+extern struct mtx afs_global_mtx;
+#define AFS_GLOCK() mtx_lock(&afs_global_mtx)
+#define AFS_GUNLOCK() mtx_unlock(&afs_global_mtx)
+#define ISAFS_GLOCK() (mtx_owned(&afs_global_mtx))
 
 #else /* FBSD50 */
+extern struct lock afs_global_lock;
 
 #define osi_curcred()	(curproc->p_cred->pc_ucred)
 #define getpid()	curproc
Index: src/afs/FBSD/osi_misc.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_misc.c,v
retrieving revision 1.8
diff -u -r1.8 osi_misc.c
--- src/afs/FBSD/osi_misc.c	15 Jul 2003 23:14:19 -0000	1.8
+++ src/afs/FBSD/osi_misc.c	29 Sep 2003 03:45:35 -0000
@@ -53,7 +53,12 @@
 	       struct vnode **dirvpp, struct vnode **vpp)
 {
     struct nameidata n;
-    int flags, error;
+    int flags, error, wasowned;
+
+    wasowned = mtx_owned(&afs_global_mtx);
+    if (wasowned)
+	mtx_unlock(&afs_global_mtx);
+
     flags = 0;
     flags = LOCKLEAF;
     if (followlink)
@@ -62,8 +67,11 @@
 	flags |= NOFOLLOW;
     /*   if (dirvpp) flags|=WANTPARENT; *//* XXX LOCKPARENT? */
     NDINIT(&n, LOOKUP, flags, seg, aname, curproc);
-    if (error = namei(&n))
+    if ((error = namei(&n)) != 0) {
+	if (wasowned)
+	    mtx_lock(&afs_global_mtx);
 	return error;
+    }
     *vpp = n.ni_vp;
 /*
    if (dirvpp)
@@ -72,6 +80,8 @@
     /* should we do this? */
     VOP_UNLOCK(n.ni_vp, 0, curproc);
     NDFREE(&n, NDF_ONLY_PNBUF);
+    if (wasowned)
+	mtx_lock(&afs_global_mtx);
     return 0;
 }
 
@@ -102,4 +112,73 @@
     resettodr();
     AFS_GLOCK();
 #endif
+}
+
+/*
+ * Replace all of the bogus special-purpose memory allocators...
+ */
+void *
+osi_fbsd_alloc(size_t size, int dropglobal)
+{
+	void *rv;
+	int wasowned;
+
+	if (dropglobal) {
+		wasowned = mtx_owned(&afs_global_mtx);
+		if (wasowned)
+			mtx_unlock(&afs_global_mtx);
+		rv = malloc(size, M_AFS, M_WAITOK);
+		if (wasowned)
+			mtx_lock(&afs_global_mtx);
+	} else
+		rv = malloc(size, M_AFS, M_NOWAIT);
+
+	return (rv);
+}
+
+void
+osi_fbsd_free(void *p)
+{
+
+	free(p, M_AFS);
+}
+
+void
+osi_AllocMoreSSpace(afs_int32 preallocs)
+{
+	;
+}
+
+void
+osi_FreeLargeSpace(void *p)
+{
+	osi_fbsd_free(p);
+}
+
+void
+osi_FreeSmallSpace(void *p)
+{
+	osi_fbsd_free(p);
+}
+
+void *
+osi_AllocLargeSpace(size_t size)
+{
+	AFS_ASSERT_GLOCK();
+	AFS_STATCNT(osi_AllocLargeSpace);
+	return (osi_fbsd_alloc(size, 1));
+}
+
+void *
+osi_AllocSmallSpace(size_t size)
+{
+	AFS_ASSERT_GLOCK();
+	AFS_STATCNT(osi_AllocSmallSpace);
+	return (osi_fbsd_alloc(size, 1));
+}
+
+void
+shutdown_osinet(void)
+{
+	;
 }
Index: src/afs/FBSD/osi_module.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_module.c,v
retrieving revision 1.4
diff -u -r1.4 osi_module.c
--- src/afs/FBSD/osi_module.c	15 Jul 2003 23:14:20 -0000	1.4
+++ src/afs/FBSD/osi_module.c	29 Sep 2003 03:45:35 -0000
@@ -60,8 +60,10 @@
 	vfs_register(&afs_vfsconf);	/* doesn't fail */
 	vfs_add_vnodeops(&afs_vnodeop_opv_desc);
 	osi_Init();
+#ifdef DO_NOT_EVER_EVER_DO_THIS
 	sysent[SYS_setgroups].sy_call = Afs_xsetgroups;
 	sysent[SYS_ioctl].sy_call = afs_xioctl;
+#endif
 	old_handler = sysent[AFS_SYSCALL].sy_call;
 	sysent[AFS_SYSCALL].sy_call = afs3_syscall;
 	sysent[AFS_SYSCALL].sy_narg = 5;
Index: src/afs/FBSD/osi_prototypes.h
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_prototypes.h,v
retrieving revision 1.4
diff -u -r1.4 osi_prototypes.h
--- src/afs/FBSD/osi_prototypes.h	15 Jul 2003 23:14:20 -0000	1.4
+++ src/afs/FBSD/osi_prototypes.h	29 Sep 2003 03:45:35 -0000
@@ -20,8 +20,14 @@
 /* osi_misc.c */
 extern int osi_lookupname(char *aname, enum uio_seg seg, int followlink,
 			  struct vnode **dirvpp, struct vnode **vpp);
+extern void *osi_fbsd_alloc(size_t size, int dropglobal);
+extern void osi_fbsd_free(void *p);
 
 /* osi_vfsops.c */
+#ifdef AFS_FBSD50_ENV
+extern int afs_statfs(struct mount *mp, struct statfs *abp, struct thread *th);
+#else
 extern int afs_statfs(struct mount *mp, struct statfs *abp, struct proc *p);
+#endif
 
 #endif /* _OSI_PROTO_H_ */
Index: src/afs/FBSD/osi_sleep.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_sleep.c,v
retrieving revision 1.10
diff -u -r1.10 osi_sleep.c
--- src/afs/FBSD/osi_sleep.c	15 Jul 2003 23:14:20 -0000	1.10
+++ src/afs/FBSD/osi_sleep.c	29 Sep 2003 03:45:36 -0000
@@ -18,32 +18,31 @@
 #include "afsincludes.h"	/* Afs-based standard headers */
 #include "afs/afs_stats.h"	/* afs statistics */
 
-
-
-static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
-
-static char waitV;
-
-
 void
 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
 {
     AFS_STATCNT(osi_InitWaitHandle);
-    achandle->proc = (caddr_t) 0;
+    cv_init(&achandle->wh_condvar, "afscondvar");
+    achandle->wh_inited = 1;
 }
 
 /* cancel osi_Wait */
+/* XXX
+ * I can't tell -- is this supposed to be cv_signal() or cv_waitq_remove()?
+ * Or perhaps cv_broadcast()?
+ * Assuming cv_signal() is the desired meaning.  -GAW
+ */
 void
 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
 {
-    caddr_t proc;
 
     AFS_STATCNT(osi_CancelWait);
-    proc = achandle->proc;
-    if (proc == 0)
+    /* XXX should not be necessary */
+    if (!achandle->wh_inited)
 	return;
-    achandle->proc = (caddr_t) 0;	/* so dude can figure out he was signalled */
-    afs_osi_Wakeup(&waitV);
+
+    AFS_ASSERT_GLOCK();
+    cv_signal(&achandle->wh_condvar);
 }
 
 /* afs_osi_Wait
@@ -54,31 +53,36 @@
 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
 {
     int code;
-    afs_int32 endTime;
+    struct timeval tv;
+    int ticks;
 
     AFS_STATCNT(osi_Wait);
-    endTime = osi_Time() + (ams / 1000);
-    if (ahandle)
-	ahandle->proc = (caddr_t) curproc;
-    do {
-	AFS_ASSERT_GLOCK();
-	code = 0;
-	code = osi_TimedSleep(&waitV, ams, aintok);
 
-	if (code)
-	    break;		/* if something happened, quit now */
-	/* if we we're cancelled, quit now */
-	if (ahandle && (ahandle->proc == (caddr_t) 0)) {
-	    /* we've been signalled */
-	    break;
-	}
-    } while (osi_Time() < endTime);
+    tv.tv_sec = ams / 1000;
+    tv.tv_usec = (ams % 1000) * 1000;
+    ticks = tvtohz(&tv);
+
+    AFS_ASSERT_GLOCK();
+    if (ahandle == NULL) {
+	/* This is nasty and evil and rude. */
+	code = msleep(&tv, &afs_global_mtx, (aintok ? PPAUSE|PCATCH : PVFS),
+	    "afswait", ticks);
+    } else {
+	if (!ahandle->wh_inited)
+	    afs_osi_InitWaitHandle(ahandle);	/* XXX should not be needed */
+
+	if (aintok)
+	    code = cv_timedwait_sig(&ahandle->wh_condvar, &afs_global_mtx,
+		ticks);
+	else
+	    code = cv_timedwait(&ahandle->wh_condvar, &afs_global_mtx, ticks);
+    }
     return code;
 }
 
-
-
-
+/*
+ * All this gluck should probably also be replaced with CVs.
+ */
 typedef struct afs_event {
     struct afs_event *next;	/* next in hash chain */
     char *event;		/* lwp event: an address */
@@ -140,9 +144,7 @@
     seq = evp->seq;
     while (seq == evp->seq) {
 	AFS_ASSERT_GLOCK();
-	AFS_GUNLOCK();
-	tsleep(event, PVFS, "afs_osi_Sleep", 0);
-	AFS_GLOCK();
+	msleep(event, &afs_global_mtx, PVFS, "afsslp", 0);
     }
     relevent(evp);
 }
@@ -153,42 +155,6 @@
     afs_osi_Sleep(event);
     return 0;
 }
-
-/* osi_TimedSleep
- * 
- * Arguments:
- * event - event to sleep on
- * ams --- max sleep time in milliseconds
- * aintok - 1 if should sleep interruptibly
- *
- * Returns 0 if timeout and EINTR if signalled.
- */
-static int
-osi_TimedSleep(char *event, afs_int32 ams, int aintok)
-{
-    int code = 0;
-    struct afs_event *evp;
-    int ticks;
-    int seq, prio;
-
-    ticks = (ams * afs_hz) / 1000;
-
-
-    evp = afs_getevent(event);
-    seq = evp->seq;
-    AFS_GUNLOCK();
-    if (aintok)
-	prio = PCATCH | PPAUSE;
-    else
-	prio = PVFS;
-    code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
-    AFS_GLOCK();
-    if (seq == evp->seq)
-	code = EINTR;
-    relevent(evp);
-    return code;
-}
-
 
 int
 afs_osi_Wakeup(void *event)
Index: src/afs/FBSD/osi_vfsops.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_vfsops.c,v
retrieving revision 1.14
diff -u -r1.14 osi_vfsops.c
--- src/afs/FBSD/osi_vfsops.c	15 Jul 2003 23:14:20 -0000	1.14
+++ src/afs/FBSD/osi_vfsops.c	29 Sep 2003 03:45:36 -0000
@@ -16,48 +16,42 @@
 struct mount *afs_globalVFS = 0;
 int afs_pbuf_freecnt = -1;
 
+#ifdef AFS_FBSD50_ENV
+#define	THREAD_OR_PROC struct thread *p
+#else
+#define	THREAD_OR_PROC struct proc *p
+#endif
+
 int
-afs_quotactl()
+afs_quotactl(struct mount *mp, int c, uid_t u, caddr_t data, THREAD_OR_PROC)
 {
     return EOPNOTSUPP;
 }
 
 int
-afs_fhtovp(mp, fhp, vpp)
-     struct mount *mp;
-     struct fid *fhp;
-     struct vnode **vpp;
+afs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
 {
 
     return (EINVAL);
 }
 
 int
-afs_vptofh(vp, fhp)
-     struct vnode *vp;
-     struct fid *fhp;
+afs_vptofh(struct vnode *vp, struct fid *fhp)
 {
 
     return (EINVAL);
 }
 
 int
-afs_start(mp, flags, p)
-     struct mount *mp;
-     int flags;
-     struct proc *p;
+afs_start(struct mount *mp, int flags, THREAD_OR_PROC)
 {
     afs_pbuf_freecnt = nswbuf / 2 + 1;
     return (0);			/* nothing to do. ? */
 }
 
 int
-afs_mount(mp, path, data, ndp, p)
-     register struct mount *mp;
-     char *path;
-     caddr_t data;
-     struct nameidata *ndp;
-     struct proc *p;
+afs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp,
+	THREAD_OR_PROC)
 {
     /* ndp contains the mounted-from device.  Just ignore it.
      * we also don't care about our proc struct. */
@@ -91,12 +85,16 @@
 }
 
 int
-afs_unmount(mp, flags, p)
-     struct mount *mp;
-     int flags;
-     struct proc *p;
+afs_unmount(struct mount *mp, int flags, THREAD_OR_PROC)
 {
 
+    /*
+     * Releaase any remaining vnodes on this mount point.
+     * The `1' means that we hold one extra reference on
+     * the root vnode (this is just a guess right now).
+     * This has to be done outside the global lock.
+     */
+    vflush(mp, 1, (flags & MNT_FORCE) ? FORCECLOSE : 0);
     AFS_GLOCK();
     AFS_STATCNT(afs_unmount);
     afs_globalVFS = 0;
@@ -151,7 +149,7 @@
 	AFS_GLOCK();
 	afs_globalVFS = mp;
 	*vpp = AFSTOV(tvp);
-	tvp->v.v_flag |= VROOT;
+	tvp->v->v_flag |= VROOT;
     }
 
     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *vpp,
@@ -160,15 +158,10 @@
     return error;
 }
 
+#ifndef AFS_FBSD50_ENV
 int
-afs_vget(mp, lfl, vp)
-     struct mount *mp;
-     struct vnode *vp;
-     int lfl;
+afs_vget(struct mount *mp, ino_t ino, int flags, struct vnode *vp)
 {
-#ifdef AFS_FBSD50_ENV
-    return EOPNOTSUPP;
-#else
     int error;
 
     printf("vget called. help!\n");
@@ -180,11 +173,11 @@
     if (!error)
 	insmntque(vp, afs_globalVFS);	/* take off free list */
     return error;
-#endif
 }
+#endif
 
 int
-afs_statfs(struct mount *mp, struct statfs *abp, struct proc *p)
+afs_statfs(struct mount *mp, struct statfs *abp, THREAD_OR_PROC)
 {
     AFS_GLOCK();
     AFS_STATCNT(afs_statfs);
@@ -217,23 +210,12 @@
 }
 
 int
-afs_sync(mp, waitfor, cred, p)
-     struct mount *mp;
-     int waitfor;
-     struct ucred *cred;
-     struct prioc *p;
+afs_sync(struct mount *mp, int waitfor, struct ucred *cred, THREAD_OR_PROC)
 {
     return 0;
 }
 
 int
-afs_sysctl()
-{
-    return EOPNOTSUPP;
-}
-
-
-int
 afs_init(struct vfsconf *vfc)
 {
     return 0;
@@ -247,7 +229,11 @@
     afs_quotactl,
     afs_statfs,
     afs_sync,
+#ifdef AFS_FBSD50_ENV
+    NULL,
+#else
     afs_vget,
+#endif
     afs_fhtovp,
 #ifdef AFS_FBSD50_ENV
     vfs_stdcheckexp,
@@ -255,7 +241,6 @@
     afs_vptofh,
     afs_init,
 #ifdef AFS_FBSD50_ENV
-    vfs_stduninit,
+    vfs_stduninit
 #endif
-    afs_sysctl
 };
Index: src/afs/FBSD/osi_vm.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_vm.c,v
retrieving revision 1.10
diff -u -r1.10 osi_vm.c
--- src/afs/FBSD/osi_vm.c	15 Jul 2003 23:14:20 -0000	1.10
+++ src/afs/FBSD/osi_vm.c	29 Sep 2003 03:45:36 -0000
@@ -32,6 +32,31 @@
 #include <limits.h>
 #include <float.h>
 
+/*
+ * FreeBSD implementation notes:
+ * Most of these operations require us to frob vm_objects.  Most
+ * functions require that the object be locked (with VM_OBJECT_LOCK)
+ * on entry and leave it locked on exit.  In order to get the
+ * vm_object itself we call VOP_GETVOBJECT on the vnode; the
+ * locking protocol requires that we do so with the heavy vnode lock
+ * held and the vnode interlock unlocked, and it returns the same
+ * way.
+ *
+ * The locking protocol for vnodes is defined in
+ * kern/vnode_if.src and sys/vnode.h; the locking is still a work in 
+ * progress, so some fields are (as of 5.1) still protected by Giant
+ * rather than an explicit lock.
+ */
+
+#define	lock_vnode(v)	vn_lock((v), LK_EXCLUSIVE | LK_RETRY, curthread)
+#define unlock_vnode(v)	VOP_UNLOCK((v), 0, curthread)
+
+#ifndef AFS_FBSD50_ENV
+/* need splvm() protection? */
+#define	VM_OBJECT_LOCK(o)
+#define VM_OBJECT_UNLOCK(o)
+#endif
+
 /* Try to discard pages, in order to recycle a vcache entry.
  *
  * We also make some sanity checks:  ref count, open count, held locks.
@@ -47,6 +72,8 @@
  * therefore obsolescent.
  *
  * OSF/1 Locking:  VN_LOCK has been called.
+ * XXX - should FreeBSD have done this, too?  Certainly looks like it.
+ * Maybe better to just call vnode_pager_setsize()?
  */
 int
 osi_VM_FlushVCache(struct vcache *avc, int *slept)
@@ -65,8 +92,9 @@
 
     AFS_GUNLOCK();
     vp = AFSTOV(avc);
-    simple_lock(&vp->v_interlock);
+    lock_vnode(vp);
     if (VOP_GETVOBJECT(vp, &obj) == 0) {
+	VM_OBJECT_LOCK(obj);
 	vm_object_page_remove(obj, 0, 0, FALSE);
 #if 0
 	if (obj->ref_count == 0) {
@@ -76,8 +104,9 @@
 	    SetAfsVnode(vp);
 	}
 #endif
+	VM_OBJECT_UNLOCK(obj);
     }
-    simple_unlock(&vp->v_interlock);
+    unlock_vnode(vp);
     AFS_GLOCK();
 
     return 0;
@@ -99,25 +128,37 @@
     AFS_GUNLOCK();
     tries = 5;
     vp = AFSTOV(avc);
+
+    /*
+     * I don't understand this.  Why not just call vm_object_page_clean()
+     * and be done with it?  I particularly don't understand why we're calling
+     * vget() here.  Is there some reason to believe that the vnode might
+     * be being recycled at this point?  I don't think there's any need for
+     * this loop, either -- if we keep the vnode locked all the time,
+     * that and the object lock will prevent any new pages from appearing.
+     * The loop is what causes the race condition.  -GAW
+     */
     do {
 	anyio = 0;
-	simple_lock(&vp->v_interlock);
+	lock_vnode(vp);
 	if (VOP_GETVOBJECT(vp, &obj) == 0 && (obj->flags & OBJ_MIGHTBEDIRTY)) {
+	    /* XXX - obj locking? */
+	    unlock_vnode(vp);
 #ifdef AFS_FBSD50_ENV
-	    if (!vget(vp, LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY, curthread)) {
+	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY, curthread)) {
 #else
-	    if (!vget
-		(vp, LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ,
-		 curproc)) {
+	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ, curproc)) {
 #endif
 		if (VOP_GETVOBJECT(vp, &obj) == 0) {
+		    VM_OBJECT_LOCK(obj);
 		    vm_object_page_clean(obj, 0, 0, OBJPC_SYNC);
+		    VM_OBJECT_UNLOCK(obj);
 		    anyio = 1;
 		}
 		vput(vp);
 	    }
 	} else
-	    simple_unlock(&vp->v_interlock);
+	    unlock_vnode(vp);
     } while (anyio && (--tries > 0));
     AFS_GLOCK();
     ObtainWriteLock(&avc->lock, 94);
@@ -145,29 +186,41 @@
     vp = AFSTOV(avc);
     do {
 	anyio = 0;
-	simple_lock(&vp->v_interlock);
+	lock_vnode(vp);
+	/* See the comments above. */
 	if (VOP_GETVOBJECT(vp, &obj) == 0 && (obj->flags & OBJ_MIGHTBEDIRTY)) {
+	    /* XXX - obj locking */
+	    unlock_vnode(vp);
 #ifdef AFS_FBSD50_ENV
-	    if (!vget(vp, LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY, curthread)) {
+	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY, curthread)) {
 #else
-	    if (!vget
-		(vp, LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ,
-		 curproc)) {
+	    if (!vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ, curproc)) {
 #endif
 		if (VOP_GETVOBJECT(vp, &obj) == 0) {
+		    VM_OBJECT_LOCK(obj);
+		    /*
+		     * Do we really want OBJPC_SYNC?  OBJPC_INVAL would be
+		     * faster, if invalidation is really what we are being
+		     * asked to do.  (It would make more sense, too, since
+		     * otherwise this function is practically identical to
+		     * osi_VM_StoreAllSegments().)  -GAW
+		     */
 		    vm_object_page_clean(obj, 0, 0, OBJPC_SYNC);
+		    VM_OBJECT_UNLOCK(obj);
 		    anyio = 1;
 		}
 		vput(vp);
 	    }
 	} else
-	    simple_unlock(&vp->v_interlock);
+	    unlock_vnode(vp);
     } while (anyio && (--tries > 0));
-    simple_lock(&vp->v_interlock);
+    lock_vnode(vp);
     if (VOP_GETVOBJECT(vp, &obj) == 0) {
+	VM_OBJECT_LOCK(obj);
 	vm_object_page_remove(obj, 0, 0, FALSE);
+	VM_OBJECT_UNLOCK(obj);
     }
-    simple_unlock(&vp->v_interlock);
+    unlock_vnode(vp);
     /*vinvalbuf(AFSTOV(avc),0, NOCRED, curproc, 0,0); */
     AFS_GLOCK();
     ObtainWriteLock(&avc->lock, 59);
@@ -184,11 +237,13 @@
     struct vm_object *obj;
 
     vp = AFSTOV(avc);
-    simple_lock(&vp->v_interlock);
+    lock_vnode(vp);
     if (VOP_GETVOBJECT(vp, &obj) == 0) {
+	VM_OBJECT_LOCK(obj);
 	vm_object_page_remove(obj, 0, 0, FALSE);
+	VM_OBJECT_UNLOCK(obj);
     }
-    simple_unlock(&vp->v_interlock);
+    unlock_vnode(vp);
     /*vinvalbuf(AFSTOV(avc),0, NOCRED, curproc, 0,0); */
 }
 
Index: src/afs/FBSD/osi_vnodeops.c
===================================================================
RCS file: /cvs/openafs/src/afs/FBSD/osi_vnodeops.c,v
retrieving revision 1.16
diff -u -r1.16 osi_vnodeops.c
--- src/afs/FBSD/osi_vnodeops.c	27 Aug 2003 21:43:17 -0000	1.16
+++ src/afs/FBSD/osi_vnodeops.c	29 Sep 2003 03:45:38 -0000
@@ -1,3 +1,49 @@
+/*
+ * A large chunk of this file appears to be copied directly from
+ * sys/nfsclient/nfs_bio.c, which has the following license:
+ */
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)nfs_bio.c	8.9 (Berkeley) 3/30/95
+ */
+/*
+ * Pursuant to a statement of U.C. Berkeley dated 1999-07-22, this license
+ * is amended to drop clause (3) above.
+ */
+
 #include <afsconfig.h>
 #include <afs/param.h>
 
@@ -9,6 +55,7 @@
 #include <afs/afs_stats.h>	/* statistics */
 #include <sys/malloc.h>
 #include <sys/namei.h>
+#include <sys/unistd.h>
 #ifndef AFS_FBSD50_ENV
 #include <vm/vm_zone.h>
 #endif
@@ -31,6 +78,7 @@
 int afs_vop_getpages(struct vop_getpages_args *);
 int afs_vop_putpages(struct vop_putpages_args *);
 int afs_vop_ioctl(struct vop_ioctl_args *);
+static int afs_vop_pathconf(struct vop_pathconf_args *);
 int afs_vop_poll(struct vop_poll_args *);
 #ifndef AFS_FBSD50_ENV
 int afs_vop_mmap(struct vop_mmap_args *);
@@ -87,6 +135,7 @@
     {&vop_mmap_desc, (vop_t *) afs_vop_mmap},	/* mmap */
 #endif
     {&vop_open_desc, (vop_t *) afs_vop_open},	/* open */
+    {&vop_pathconf_desc, (vop_t *) afs_vop_pathconf},	/* pathconf */
     {&vop_poll_desc, (vop_t *) afs_vop_poll},	/* select */
     {&vop_print_desc, (vop_t *) afs_vop_print},	/* print */
     {&vop_read_desc, (vop_t *) afs_vop_read},	/* read */
@@ -122,7 +171,98 @@
 #define a_p a_td
 #endif
 
+/*
+ * Mosty copied from sys/ufs/ufs/ufs_vnops.c:ufs_pathconf().
+ * We should know the correct answers to these questions with
+ * respect to the AFS protocol (which may differ from the UFS
+ * values) but for the moment this will do.
+ */
+static int
+afs_vop_pathconf(struct vop_pathconf_args *ap)
+{
+	int error;
 
+	error = 0;
+	switch (ap->a_name) {
+	case _PC_LINK_MAX:
+		*ap->a_retval = LINK_MAX;
+		break;
+	case _PC_NAME_MAX:
+		*ap->a_retval = NAME_MAX;
+		break;
+	case _PC_PATH_MAX:
+		*ap->a_retval = PATH_MAX;
+		break;
+	case _PC_PIPE_BUF:
+		*ap->a_retval = PIPE_BUF;
+		break;
+	case _PC_CHOWN_RESTRICTED:
+		*ap->a_retval = 1;
+		break;
+	case _PC_NO_TRUNC:
+		*ap->a_retval = 1;
+		break;
+#ifdef _PC_ACL_EXTENDED
+	case _PC_ACL_EXTENDED:
+		*ap->a_retval = 0;
+		break;
+	case _PC_ACL_PATH_MAX:
+		*ap->a_retval = 3;
+		break;
+#endif
+#ifdef _PC_MAC_PRESENT
+	case _PC_MAC_PRESENT:
+		*ap->a_retval = 0;
+		break;
+#endif
+#ifdef _PC_ASYNC_IO
+	case _PC_ASYNC_IO:
+		/* _PC_ASYNC_IO should have been handled by upper layers. */
+		KASSERT(0, ("_PC_ASYNC_IO should not get here"));
+		error = EINVAL;
+		break;
+	case _PC_PRIO_IO:
+		*ap->a_retval = 0;
+		break;
+	case _PC_SYNC_IO:
+		*ap->a_retval = 0;
+		break;
+#endif
+#ifdef _PC_ALLOC_SIZE_MIN
+	case _PC_ALLOC_SIZE_MIN:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
+		break;
+#endif
+#ifdef _PC_FILESIZEBITS
+	case _PC_FILESIZEBITS:
+		*ap->a_retval = 32; /* XXX */
+		break;
+#endif
+#ifdef _PC_REC_INCR_XFER_SIZE
+	case _PC_REC_INCR_XFER_SIZE:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
+		break;
+	case _PC_REC_MAX_XFER_SIZE:
+		*ap->a_retval = -1; /* means ``unlimited'' */
+		break;
+	case _PC_REC_MIN_XFER_SIZE:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
+		break;
+	case _PC_REC_XFER_ALIGN:
+		*ap->a_retval = PAGE_SIZE;
+		break;
+#endif
+#ifdef _PC_SYMLINK_MAX
+	case _PC_SYMLINK_MAX:
+		*ap->a_retval = MAXPATHLEN;
+		break;
+#endif
+	default:
+		error = EINVAL;
+		break;
+	}
+	return (error);
+}
 
 int
 afs_vop_lookup(ap)
@@ -397,15 +537,16 @@
     return code;
 }
 
+/* struct vop_getpages_args {
+ *	struct vnode *a_vp;
+ *	vm_page_t *a_m;
+ *	int a_count;
+ *	int a_reqpage;
+ *	vm_oofset_t a_offset;
+ * };
+ */
 int
-afs_vop_getpages(ap)
-     struct vop_getpages_args	/* {
-				 * struct vnode *a_vp;
-				 * vm_page_t *a_m;
-				 * int a_count;
-				 * int a_reqpage;
-				 * vm_oofset_t a_offset;
-				 * } */ *ap;
+afs_vop_getpages(struct vop_getpages_args *ap)
 {
     int code;
     int i, nextoff, size, toff, npages;
@@ -413,9 +554,16 @@
     struct iovec iov;
     struct buf *bp;
     vm_offset_t kva;
-    struct vcache *avc = VTOAFS(ap->a_vp);
+    vm_object_t object;
+    struct vnode *vp;
+    struct vcache *avc;
 
-    if (avc->v.v_object == NULL) {
+#ifdef AFS_FBSD50_ENV
+    GIANT_REQUIRED;
+#endif
+    vp = ap->a_vp;
+    avc = VTOAFS(vp);
+    if ((object = vp->v_object) == NULL) {
 	printf("afs_getpages: called with non-merged cache vnode??\n");
 	return VM_PAGER_ERROR;
     }
@@ -429,6 +577,10 @@
     {
 	vm_page_t m = ap->a_m[ap->a_reqpage];
 
+#ifdef AFS_FBSD50_ENV
+	VM_OBJECT_LOCK(object);
+	vm_page_lock_queues();
+#endif
 	if (m->valid != 0) {
 	    /* handled by vm_fault now        */
 	    /* vm_page_zero_invalid(m, TRUE); */
@@ -436,12 +588,24 @@
 		if (i != ap->a_reqpage)
 		    vm_page_free(ap->a_m[i]);
 	    }
+#ifdef AFS_FBSD50_ENV
+	    vm_page_unlock_queues();
+	    VM_OBJECT_UNLOCK(object);
+#endif
 	    return (0);
 	}
+#ifdef AFS_FBSD50_ENV
+	vm_page_unlock_queues();
+	VM_OBJECT_UNLOCK(object);
+#endif
     }
     bp = getpbuf(&afs_pbuf_freecnt);
+
     kva = (vm_offset_t) bp->b_data;
     pmap_qenter(kva, ap->a_m, npages);
+    cnt.v_vnodein++;
+    cnt.v_vnodepgsin += npages;
+
     iov.iov_base = (caddr_t) kva;
     iov.iov_len = ap->a_count;
     uio.uio_iov = &iov;
@@ -455,6 +619,7 @@
 #else
     uio.uio_procp = curproc;
 #endif
+
     AFS_GLOCK();
     afs_BozonLock(&avc->pvnLock, avc);
     osi_FlushPages(avc, osi_curcred());	/* hold bozon lock, but not basic vnode lock */
@@ -464,14 +629,28 @@
     pmap_qremove(kva, npages);
 
     relpbuf(bp, &afs_pbuf_freecnt);
+
     if (code && (uio.uio_resid == ap->a_count)) {
+#ifdef AFS_FBSD50_ENV
+	VM_OBJECT_LOCK(object);
+	vm_page_lock_queues();
+#endif
 	for (i = 0; i < npages; ++i) {
 	    if (i != ap->a_reqpage)
 		vm_page_free(ap->a_m[i]);
 	}
+#ifdef AFS_FBSD50_ENV
+	vm_page_unlock_queues();
+	VM_OBJECT_UNLOCK(object);
+#endif
 	return VM_PAGER_ERROR;
     }
+
     size = ap->a_count - uio.uio_resid;
+#ifdef AFS_FBSD50_ENV
+    VM_OBJECT_LOCK(object);
+    vm_page_lock_queues();
+#endif
     for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
 	vm_page_t m;
 	nextoff = toff + PAGE_SIZE;
@@ -519,6 +698,10 @@
 	    }
 	}
     }
+#ifdef AFS_FBSD50_ENV
+    vm_page_unlock_queues();
+    VM_OBJECT_UNLOCK(object);
+#endif
     return 0;
 }
 
@@ -543,16 +726,22 @@
     return code;
 }
 
+/*-
+ * struct vop_putpages_args {
+ *	struct vnode *a_vp;
+ *	vm_page_t *a_m;
+ *	int a_count;
+ *	int a_sync;
+ *	int *a_rtvals;
+ *	vm_oofset_t a_offset;
+ * };
+ */
+/*
+ * All of the pages passed to us in ap->a_m[] are already marked as busy,
+ * so there is no additional locking required to set their flags.  -GAW
+ */
 int
-afs_vop_putpages(ap)
-     struct vop_putpages_args	/* {
-				 * struct vnode *a_vp;
-				 * vm_page_t *a_m;
-				 * int a_count;
-				 * int a_sync;
-				 * int *a_rtvals;
-				 * vm_oofset_t a_offset;
-				 * } */ *ap;
+afs_vop_putpages(struct vop_putpages_args *ap)
 {
     int code;
     int i, size, npages, sync;
@@ -560,22 +749,34 @@
     struct iovec iov;
     struct buf *bp;
     vm_offset_t kva;
-    struct vcache *avc = VTOAFS(ap->a_vp);
+    struct vnode *vp;
+    struct vcache *avc;
+
+#ifdef AFS_FBSD50_ENV
+    GIANT_REQUIRED;
+#endif
 
-    if (avc->v.v_object == NULL) {
+    vp = ap->a_vp;
+    avc = VTOAFS(vp);
+    /* Perhaps these two checks should just be KASSERTs instead... */
+    if (vp->v_object == NULL) {
 	printf("afs_putpages: called with non-merged cache vnode??\n");
-	return VM_PAGER_ERROR;
+	return VM_PAGER_ERROR;	/* XXX I think this is insufficient */
     }
     if (vType(avc) != VREG) {
 	printf("afs_putpages: not VREG");
-	return VM_PAGER_ERROR;
+	return VM_PAGER_ERROR;	/* XXX I think this is insufficient */
     }
     npages = btoc(ap->a_count);
     for (i = 0; i < npages; i++)
 	ap->a_rtvals[i] = VM_PAGER_AGAIN;
     bp = getpbuf(&afs_pbuf_freecnt);
+
     kva = (vm_offset_t) bp->b_data;
     pmap_qenter(kva, ap->a_m, npages);
+    cnt.v_vnodeout++;
+    cnt.v_vnodepgsout += ap->a_count;
+
     iov.iov_base = (caddr_t) kva;
     iov.iov_len = ap->a_count;
     uio.uio_iov = &iov;
@@ -600,16 +801,16 @@
     code = afs_write(avc, &uio, sync, osi_curcred(), 0);
     afs_BozonUnlock(&avc->pvnLock, avc);
     AFS_GUNLOCK();
-    pmap_qremove(kva, npages);
 
+    pmap_qremove(kva, npages);
     relpbuf(bp, &afs_pbuf_freecnt);
+
     if (!code) {
 	size = ap->a_count - uio.uio_resid;
 	for (i = 0; i < round_page(size) / PAGE_SIZE; i++) {
 	    ap->a_rtvals[i] = VM_PAGER_OK;
-	    ap->a_m[i]->dirty = 0;
+	    vm_page_undirty(ap->a_m[i]);
 	}
-	return VM_PAGER_ERROR;
     }
     return ap->a_rtvals[0];
 }
@@ -1091,6 +1292,7 @@
     if (vp->v_tag == VT_NON)
 #endif
 	return (ENOENT);
+    KASSERT(avc != NULL, ("afs_vop_lock: null vcache"));
     return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
 }
 
Index: src/config/param.i386_fbsd_42.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_42.h,v
retrieving revision 1.9
diff -u -r1.9 param.i386_fbsd_42.h
--- src/config/param.i386_fbsd_42.h	15 Jul 2003 23:14:55 -0000	1.9
+++ src/config/param.i386_fbsd_42.h	29 Sep 2003 03:45:39 -0000
@@ -79,8 +79,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define	AFS_KALLOC(x)	malloc(x, M_AFS, M_WAITOK)
-#define	AFS_KFREE(x,y)	free(x,M_AFS)
+#define	AFS_KALLOC(x)	osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x)	osi_fbsd_alloc((x), 0)
+#define	AFS_KFREE(x,y)	osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_43.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_43.h,v
retrieving revision 1.6
diff -u -r1.6 param.i386_fbsd_43.h
--- src/config/param.i386_fbsd_43.h	15 Jul 2003 23:14:55 -0000	1.6
+++ src/config/param.i386_fbsd_43.h	29 Sep 2003 03:45:39 -0000
@@ -81,8 +81,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_44.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_44.h,v
retrieving revision 1.6
diff -u -r1.6 param.i386_fbsd_44.h
--- src/config/param.i386_fbsd_44.h	15 Jul 2003 23:14:55 -0000	1.6
+++ src/config/param.i386_fbsd_44.h	29 Sep 2003 03:45:39 -0000
@@ -83,8 +83,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_45.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_45.h,v
retrieving revision 1.7
diff -u -r1.7 param.i386_fbsd_45.h
--- src/config/param.i386_fbsd_45.h	15 Jul 2003 23:14:55 -0000	1.7
+++ src/config/param.i386_fbsd_45.h	29 Sep 2003 03:45:39 -0000
@@ -84,8 +84,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_46.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_46.h,v
retrieving revision 1.6
diff -u -r1.6 param.i386_fbsd_46.h
--- src/config/param.i386_fbsd_46.h	15 Jul 2003 23:14:55 -0000	1.6
+++ src/config/param.i386_fbsd_46.h	29 Sep 2003 03:45:39 -0000
@@ -85,8 +85,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_47.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_47.h,v
retrieving revision 1.4
diff -u -r1.4 param.i386_fbsd_47.h
--- src/config/param.i386_fbsd_47.h	15 Jul 2003 23:14:55 -0000	1.4
+++ src/config/param.i386_fbsd_47.h	29 Sep 2003 03:45:39 -0000
@@ -87,8 +87,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_50.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_50.h,v
retrieving revision 1.6
diff -u -r1.6 param.i386_fbsd_50.h
--- src/config/param.i386_fbsd_50.h	15 Jul 2003 23:14:55 -0000	1.6
+++ src/config/param.i386_fbsd_50.h	29 Sep 2003 03:45:40 -0000
@@ -88,8 +88,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
Index: src/config/param.i386_fbsd_51.h
===================================================================
RCS file: /cvs/openafs/src/config/param.i386_fbsd_51.h,v
retrieving revision 1.1
diff -u -r1.1 param.i386_fbsd_51.h
--- src/config/param.i386_fbsd_51.h	17 Jul 2003 16:00:56 -0000	1.1
+++ src/config/param.i386_fbsd_51.h	29 Sep 2003 03:45:40 -0000
@@ -79,7 +79,7 @@
 #ifdef _KERNEL
 #define AFS_GLOBAL_SUNLOCK        1
 #define	AFS_VFS34	1	/* What is VFS34??? */
-#define	AFS_SHORTGID	1	/* are group id's short? */
+#define	AFS_SHORTGID	0	/* are group id's short? */
 #define	afsio_iov	uio_iov
 #define	afsio_iovcnt	uio_iovcnt
 #define	afsio_offset	uio_offset
@@ -89,8 +89,10 @@
 #define	AFS_UIOUSER	UIO_USERSPACE
 #define	AFS_CLBYTES	CLBYTES
 #define	osi_GetTime(x)	microtime(x)
-#define AFS_KALLOC(x)   malloc(x, M_AFS, M_WAITOK)
-#define AFS_KFREE(x,y)  free(x,M_AFS)
+#define AFS_KALLOC(x)   osi_fbsd_alloc((x), 1)
+#undef	AFS_KALLOC_NOSLEEP
+#define	AFS_KALLOC_NOSLEEP(x) osi_fbsd_alloc((x), 0)
+#define AFS_KFREE(x,y)  osi_fbsd_free((x))
 #define	v_count		v_usecount
 #define v_vfsp		v_mount
 #define vfs_bsize	mnt_stat.f_bsize
@@ -169,7 +171,7 @@
 #define SYS_NAME_ID	SYS_NAME_ID_i386_fbsd_51
 #define AFSLITTLE_ENDIAN    1
 #define AFS_HAVE_FFS        1	/* Use system's ffs. */
-#define AFS_HAVE_STATVFS    0	/* System doesn't support statvfs */
+#define AFS_HAVE_STATVFS    1	/* System doesn't support statvfs */
 #define AFS_VM_RDWR_ENV	    1	/* read/write implemented via VM */
 
 #define	afsio_iov	uio_iov
Index: src/libafs/MakefileProto.FBSD.in
===================================================================
RCS file: /cvs/openafs/src/libafs/MakefileProto.FBSD.in,v
retrieving revision 1.22
diff -u -r1.22 MakefileProto.FBSD.in
--- src/libafs/MakefileProto.FBSD.in	1 Jul 2003 18:06:40 -0000	1.22
+++ src/libafs/MakefileProto.FBSD.in	29 Sep 2003 03:45:41 -0000
@@ -34,9 +34,11 @@
 <i386_fbsd_42 i386_fbsd_43 i386_fbsd_44 i386_fbsd_45 i386_fbsd_46 i386_fbsd_47>
 	-fformat-extensions
 <all -i386_fbsd_42 -i386_fbsd_43 -i386_fbsd_44 -i386_fbsd_45 -i386_fbsd_46 -i386_fbsd_47>
-	-mno-align-long-strings -fformat-extensions -fno-common -ffreestanding
+	-mno-align-long-strings -fformat-extensions -fno-common -ffreestanding \
+	-I/sys/i386/compile/AFS -include opt_global.h -fno-strict-aliasing
+
 <all>
-DBUG = -O2
+DBUG = -O -g
 DEFINES= -DAFSDEBUG -DKERNEL -DAFS -DVICE -DNFS -DUFS -DINET -DQUOTA -DGETMOUNT
 OPTF=${OPT} 
 OPTF2=${OPT2} 
Index: src/libuafs/MakefileProto.FBSD.in
===================================================================
RCS file: /cvs/openafs/src/libuafs/MakefileProto.FBSD.in,v
retrieving revision 1.9
diff -u -r1.9 MakefileProto.FBSD.in
--- src/libuafs/MakefileProto.FBSD.in	10 Mar 2003 01:59:40 -0000	1.9
+++ src/libuafs/MakefileProto.FBSD.in	29 Sep 2003 03:45:41 -0000
@@ -10,16 +10,16 @@
 
 
 # System specific build commands and flags
-CC = gcc
+CC = @CC@
 DEFINES= -D_REENTRANT -DKERNEL -DUKERNEL
 KOPTS=
 CFLAGS=-I. -I.. -I${TOP_OBJDIR}/src/config ${FSINCLUDES} $(DEFINES) $(KOPTS) ${DBUG}
 OPTF=-O
 # WEBOPTS = -I../nsapi -DNETSCAPE_NSAPI -DNET_SSL -DXP_UNIX -DMCC_HTTPD
 
-TEST_CFLAGS=-pthread -D_REENTRANT -DAFS_PTHREAD_ENV -DAFS_FBSD40_ENV
+TEST_CFLAGS=-D_REENTRANT -DAFS_PTHREAD_ENV -DAFS_FBSD40_ENV
 TEST_LDFLAGS=
-TEST_LIBS=
+TEST_LIBS=-lc_r
 
 LIBUAFS = libuafs.a
 LIBJUAFS = libjuafs.a
Index: src/rx/rx_kcommon.c
===================================================================
RCS file: /cvs/openafs/src/rx/rx_kcommon.c,v
retrieving revision 1.37
diff -u -r1.37 rx_kcommon.c
--- src/rx/rx_kcommon.c	27 Aug 2003 21:43:19 -0000	1.37
+++ src/rx/rx_kcommon.c	29 Sep 2003 03:45:42 -0000
@@ -776,6 +776,8 @@
 #if (defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)) && defined(KERNEL_FUNNEL)
     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
 #endif
+    AFS_ASSERT_GLOCK();
+    AFS_GUNLOCK();
 #if	defined(AFS_HPUX102_ENV)
 #if     defined(AFS_HPUX110_ENV)
     /* blocking socket */
@@ -796,6 +798,7 @@
     if (code)
 	goto bad;
 
+    memset(&myaddr, 0, sizeof myaddr);
     myaddr.sin_family = AF_INET;
     myaddr.sin_port = aport;
     myaddr.sin_addr.s_addr = 0;
@@ -841,6 +844,7 @@
     if (code) {
 	printf("sobind fails (%d)\n", (int)code);
 	soclose(newSocket);
+        AFS_GLOCK();
 	goto bad;
     }
 #else /* defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) */
@@ -875,12 +879,14 @@
 #endif /* else AFS_DARWIN_ENV */
 #endif /* else AFS_HPUX110_ENV */
 
+    AFS_GLOCK();
 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
 #endif
     return (struct osi_socket *)newSocket;
 
   bad:
+    AFS_GLOCK();
 #if defined(AFS_DARWIN_ENV) && defined(KERNEL_FUNNEL)
     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
 #endif
Index: src/rx/rx_prototypes.h
===================================================================
RCS file: /cvs/openafs/src/rx/rx_prototypes.h,v
retrieving revision 1.12
diff -u -r1.12 rx_prototypes.h
--- src/rx/rx_prototypes.h	15 Jul 2003 23:16:10 -0000	1.12
+++ src/rx/rx_prototypes.h	29 Sep 2003 03:45:43 -0000
@@ -561,9 +561,15 @@
 
 /* EXTERNAL PROTOTYPES - include here cause it causes too many issues to
    include the afs_prototypes.h file - just make sure they match */
+#ifndef afs_osi_Alloc
 extern void *afs_osi_Alloc(size_t x);
+#endif
+#ifndef afs_osi_Alloc_NoSleep
 extern void *afs_osi_Alloc_NoSleep(size_t x);
+#endif
+#ifndef afs_osi_Free
 extern void afs_osi_Free(void *x, size_t asize);
+#endif
 #ifndef afs_osi_Wakeup
 extern int afs_osi_Wakeup(void *event);
 #endif
Index: src/rx/xdr.h
===================================================================
RCS file: /cvs/openafs/src/rx/xdr.h,v
retrieving revision 1.10
diff -u -r1.10 xdr.h
--- src/rx/xdr.h	15 Jul 2003 23:16:12 -0000	1.10
+++ src/rx/xdr.h	29 Sep 2003 03:45:43 -0000
@@ -96,7 +96,9 @@
 
 /* keep here for now, 64 bit issues */
 extern void *afs_osi_Alloc(size_t x);
+#ifndef afs_osi_Alloc_NoSleep
 extern void *afs_osi_Alloc_NoSleep(size_t x);
+#endif
 extern void afs_osi_Free(void *x, size_t asize);
 
 #endif
Index: src/rx/FBSD/rx_knet.c
===================================================================
RCS file: /cvs/openafs/src/rx/FBSD/rx_knet.c,v
retrieving revision 1.13
diff -u -r1.13 rx_knet.c
--- src/rx/FBSD/rx_knet.c	15 Jul 2003 23:16:18 -0000	1.13
+++ src/rx/FBSD/rx_knet.c	29 Sep 2003 03:45:44 -0000
@@ -83,10 +83,20 @@
 {
     struct proc *p;
 
+    /*
+     * Have to drop global lock to safely do this.
+     * soclose() is currently protected by Giant,
+     * but pfind and psignal are MPSAFE.
+     */
+    AFS_GUNLOCK();
     soclose(rx_socket);
     p = pfind(rxk_ListenerPid);
     if (p)
 	psignal(p, SIGUSR1);
+#ifdef AFS_FBSD50_ENV
+    PROC_UNLOCK(p);
+#endif
+    AFS_GLOCK();
 }
 
 int
Index: src/viced/viced.c
===================================================================
RCS file: /cvs/openafs/src/viced/viced.c,v
retrieving revision 1.51
diff -u -r1.51 viced.c
--- src/viced/viced.c	24 Sep 2003 18:54:10 -0000	1.51
+++ src/viced/viced.c	29 Sep 2003 03:45:46 -0000
@@ -1564,9 +1564,12 @@
     softsig_init();
 #endif
 
+    ViceLog(0, ("Got to point 1\n"));
     /* install signal handlers for controlling the fileserver process */
     ResetCheckSignal();		/* set CheckSignal_Signal() sig handler */
+    ViceLog(0, ("Got to point 2\n"));
     ResetCheckDescriptors();	/* set CheckDescriptors_Signal() sig handler */
+    ViceLog(0, ("Got to point 3\n"));
 
 #if defined(AFS_SGI_ENV)
     /* give this guy a non-degrading priority so help busy servers */
@@ -1577,8 +1580,10 @@
 #ifndef AFS_NT40_ENV
     nice(-5);			/* TODO: */
 #endif
+    ViceLog(0, ("Got to point 4\n"));
 #endif
     assert(DInit(buffs) == 0);
+    ViceLog(0, ("Got to point 5\n"));
 
 #ifdef AFS_NT40_ENV
     if (afs_winsockInit() < 0) {
@@ -1588,6 +1593,7 @@
     }
 #endif
     CheckAdminName();
+    ViceLog(0, ("Got to point 6\n"));
 
     /* if we support more than 16 threads, then we better have the ability 
      ** to keep open a large number of files simultaneously 
Index: src/vlserver/vlprocs.c
===================================================================
RCS file: /cvs/openafs/src/vlserver/vlprocs.c,v
retrieving revision 1.10
diff -u -r1.10 vlprocs.c
--- src/vlserver/vlprocs.c	15 Jul 2003 23:17:34 -0000	1.10
+++ src/vlserver/vlprocs.c	29 Sep 2003 03:45:48 -0000
@@ -38,6 +38,12 @@
 #ifndef AFS_NT40_ENV
 #include <unistd.h>
 #endif
+#ifdef AFS_FBSD_ENV		/* XXX for now */
+#define HAVE_REGEX_H
+#endif
+#ifdef HAVE_REGEX_H		/* use POSIX regexp library */
+#include <regex.h>
+#endif
 
 extern int smallMem;
 extern extent_mod;
@@ -1376,6 +1382,10 @@
     int pollcount = 0;
     int namematchRWBK, namematchRO, thismatch, matchtype;
     char volumename[VL_MAXNAMELEN];
+#ifdef HAVE_REGEX_H
+    regex_t re;
+    int need_regfree = 0;
+#endif
 
     COUNT_REQ(VLLISTATTRIBUTESN2);
     vldbentries->nbulkentries_val = 0;
@@ -1433,11 +1443,19 @@
 	findflag = ((attributes->Mask & VLLIST_FLAG) ? 1 : 0);
 	if (name && (strcmp(name, ".*") != 0) && (strcmp(name, "") != 0)) {
 	    sprintf(volumename, "^%s$", name);
+#ifdef HAVE_REGEX_H
+	    if (regcomp(&re, volumename, REG_BASIC | REG_NOSUB) != 0) {
+		errorcode = VL_BADNAME;
+		goto done;
+	    }
+	    need_regfree = 1;
+#else
 	    t = (char *)re_comp(volumename);
 	    if (t) {
 		errorcode = VL_BADNAME;
 		goto done;
 	    }
+#endif
 	    findname = 1;
 	}
 
@@ -1468,9 +1486,15 @@
 		    if (tentry.flags & VLF_RWEXISTS) {
 			if (findname) {
 			    sprintf(volumename, "%s", tentry.name);
+#ifdef HAVE_REGEX_H
+			    if (regexec(&re, volumename, 0, NULL, 0) == 0) {
+				thismatch = VLSF_RWVOL;
+			    }
+#else
 			    if (re_exec(volumename)) {
 				thismatch = VLSF_RWVOL;
 			    }
+#endif
 			} else {
 			    thismatch = VLSF_RWVOL;
 			}
@@ -1480,9 +1504,15 @@
 		    if (!thismatch && (tentry.flags & VLF_BACKEXISTS)) {
 			if (findname) {
 			    sprintf(volumename, "%s.backup", tentry.name);
+#ifdef HAVE_REGEX_H
+			    if (regexec(&re, volumename, 0, NULL, 0) == 0) {
+				thismatch = VLSF_BACKVOL;
+			    }
+#else
 			    if (re_exec(volumename)) {
 				thismatch = VLSF_BACKVOL;
 			    }
+#endif
 			} else {
 			    thismatch = VLSF_BACKVOL;
 			}
@@ -1504,8 +1534,14 @@
 			    } else {
 				sprintf(volumename, "%s.readonly",
 					tentry.name);
+#ifdef HAVE_REGEX_H
+			    if (regexec(&re, volumename, 0, NULL, 0) == 0) {
+				thismatch = VLSF_ROVOL;
+			    }
+#else
 				if (re_exec(volumename))
 				    thismatch = VLSF_ROVOL;
+#endif
 			    }
 			} else {
 			    thismatch = VLSF_ROVOL;
@@ -1566,6 +1602,9 @@
     }
 
   done:
+    if (need_regfree)
+	regfree(&re);
+
     if (errorcode) {
 	COUNT_ABO;
 	ubik_AbortTrans(trans);
Index: src/volser/vos.c
===================================================================
RCS file: /cvs/openafs/src/volser/vos.c,v
retrieving revision 1.28
diff -u -r1.28 vos.c
--- src/volser/vos.c	15 Sep 2003 21:39:10 -0000	1.28
+++ src/volser/vos.c	29 Sep 2003 03:45:52 -0000
@@ -62,6 +62,13 @@
 #endif
 #include "volser_prototypes.h"
 
+#ifdef AFS_FBSD_ENV
+#define HAVE_REGEX_H
+#endif
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+
 struct tqElem {
     afs_int32 volid;
     struct tqElem *next;
@@ -3928,6 +3935,20 @@
     if (seenprefix) {
 	for (ti = as->parms[0].items; ti; ti = ti->next) {
 	    if (strncmp(ti->data, "^", 1) == 0) {
+#ifdef HAVE_REGEX_H
+		regex_t re;
+		char errbuf[256];
+
+		code = regcomp(&re, ti->data, REG_BASIC | REG_NOSUB);
+		if (code != 0) {
+		    regerror(code, &re, errbuf, sizeof errbuf);
+		    fprintf(STDERR,
+			    "Unrecognizable -prefix regular expression: '%s': %s\n",
+			    ti->data, errbuf);
+		    exit(1);
+		}
+		regfree(&re);
+#else
 		ccode = (char *)re_comp(ti->data);
 		if (ccode) {
 		    fprintf(STDERR,
@@ -3935,12 +3956,27 @@
 			    ti->data, ccode);
 		    exit(1);
 		}
+#endif
 	    }
 	}
     }
     if (seenxprefix) {
 	for (ti = as->parms[4].items; ti; ti = ti->next) {
 	    if (strncmp(ti->data, "^", 1) == 0) {
+#ifdef HAVE_REGEX_H
+		regex_t re;
+		char errbuf[256];
+
+		code = regcomp(&re, ti->data, REG_BASIC | REG_NOSUB);
+		if (code != 0) {
+		    regerror(code, &re, errbuf, sizeof errbuf);
+		    fprintf(STDERR,
+			    "Unrecognizable -xprefix regular expression: '%s': %s\n",
+			    ti->data, errbuf);
+		    exit(1);
+		}
+		regfree(&re);
+#else
 		ccode = (char *)re_comp(ti->data);
 		if (ccode) {
 		    fprintf(STDERR,
@@ -3948,6 +3984,7 @@
 			    ti->data, ccode);
 		    exit(1);
 		}
+#endif
 	    }
 	}
     }
@@ -4012,6 +4049,22 @@
 	if (seenprefix) {
 	    for (ti = as->parms[0].items; ti; ti = ti->next) {
 		if (strncmp(ti->data, "^", 1) == 0) {
+#ifdef HAVE_REGEX_H
+		    regex_t re;
+		    char errbuf[256];
+
+		    /* XXX -- should just do the compile once! */
+		    code = regcomp(&re, ti->data, REG_BASIC | REG_NOSUB);
+		    if (code != 0) {
+			regerror(code, &re, errbuf, sizeof errbuf);
+			fprintf(STDERR,
+				"Error in -prefix regular expression: '%s': %s\n",
+				ti->data, errbuf);
+			exit(1);
+		    }
+		    match = (regexec(&re, vllist->name, 0, NULL, 0) == 0);
+		    regfree(&re);
+#else
 		    ccode = (char *)re_comp(ti->data);
 		    if (ccode) {
 			fprintf(STDERR,
@@ -4020,6 +4073,7 @@
 			exit(1);
 		    }
 		    match = (re_exec(vllist->name) == 1);
+#endif
 		} else {
 		    match =
 			(strncmp(vllist->name, ti->data, strlen(ti->data)) ==
@@ -4040,6 +4094,23 @@
 	if (match && seenxprefix) {
 	    for (ti = as->parms[4].items; ti; ti = ti->next) {
 		if (strncmp(ti->data, "^", 1) == 0) {
+#ifdef HAVE_REGEX_H
+		    regex_t re;
+		    char errbuf[256];
+
+		    /* XXX -- should just do the compile once! */
+		    code = regcomp(&re, ti->data, REG_BASIC | REG_NOSUB);
+		    if (code != 0) {
+			regerror(code, &re, errbuf, sizeof errbuf);
+			fprintf(STDERR,
+				"Error in -xprefix regular expression: '%s': %s\n",
+				ti->data, errbuf);
+			exit(1);
+		    }
+		    if (regexec(&re, vllist->name, 0, NULL, 0) == 0)
+			    match = 0;
+		    regfree(&re);
+#else
 		    ccode = (char *)re_comp(ti->data);
 		    if (ccode) {
 			fprintf(STDERR,
@@ -4051,6 +4122,7 @@
 			match = 0;
 			break;
 		    }
+#endif
 		} else {
 		    if (strncmp(vllist->name, ti->data, strlen(ti->data)) ==
 			0) {