[OpenAFS-port-freebsd] Making more progress....

Garrett Wollman wollman@khavrinen.lcs.mit.edu
Wed, 8 Oct 2003 01:40:52 -0400 (EDT)


Updated patch available at
<http://lcs.mit.edu/~wollman/openafs-fbsd52.patch>.  Changes in this
version:

- Doesn't crash when doing heavy recycling (e.g., listing
/afs/sipb.mit.edu/users with a small cache).

- I've rebroken shutdown (will investigate when I am sufficiently
awake again).

- Redundant vop_lock family routines eliminated (the standard ones are
just fine for our purposes).

- Includes correct fix for vop_symlink.

- Includes preliminary autoconf glue to test for POSIX regex(3),
eliminating need for libcompat.  (Same change should be made for
OpenBSD.)  Jim Rees, feel free to commit these parts.

-GAWollman

(Patch included below for ease of review/commentary....)

Index: acinclude.m4
===================================================================
RCS file: /cvs/openafs/acinclude.m4,v
retrieving revision 1.90
diff -u -r1.90 acinclude.m4
--- acinclude.m4	25 Sep 2003 16:26:10 -0000	1.90
+++ acinclude.m4	8 Oct 2003 05:09:20 -0000
@@ -806,7 +806,7 @@
 AC_CHECK_HEADERS(mntent.h sys/vfs.h sys/param.h sys/fs_types.h sys/fstyp.h)
 AC_CHECK_HEADERS(sys/mount.h strings.h termios.h signal.h)
 AC_CHECK_HEADERS(windows.h malloc.h winsock2.h direct.h io.h)
-AC_CHECK_HEADERS(security/pam_modules.h siad.h usersec.h ucontext.h)
+AC_CHECK_HEADERS(security/pam_modules.h siad.h usersec.h ucontext.h regex.h)
 
 if test "$ac_cv_header_security_pam_modules_h" = "yes"; then
 	HAVE_PAM="yes"
@@ -817,6 +817,19 @@
 
 AC_CHECK_FUNCS(utimes random srandom getdtablesize snprintf strlcat strlcpy re_comp re_exec)
 AC_CHECK_FUNCS(setprogname getprogname sigaction mkstemp vsnprintf strerror)
+
+AC_CHECK_FUNCS(regcomp regexec regerror)
+AC_MSG_CHECKING([if you have the complete POSIX regex library])
+if test "$ac_cv_header_regex_h" = "yes" && \
+	test "$ac_cv_func_regcomp" = "yes" && \
+	test "$ac_cv_func_regexec" = "yes" && \
+	test "$ac_cv_func_regerror" = "yes"; then
+    AC_DEFINE(HAVE_POSIX_REGEX)
+    AC_MSG_RESULT(yes)
+else
+    AC_MSG_RESULT(no)
+fi
+	
 AC_CHECK_TYPE(ssize_t, int)
 AC_SIZEOF_TYPE(long)
 
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	8 Oct 2003 05:09:34 -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	8 Oct 2003 05:09:36 -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	8 Oct 2003 05:09:37 -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	8 Oct 2003 05:09:38 -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	8 Oct 2003 05:09:38 -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	8 Oct 2003 05:09:39 -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	8 Oct 2003 05:09:39 -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	8 Oct 2003 05:09:42 -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_XBSD_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,40 @@
     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
+    /*
+     * XXX - I really don't like this.  Should try to understand better.
+     * It seems that sometimes, when we get called, we already hold the
+     * lock on the vnode (e.g., from afs_getattr via afs_VerifyVCache).
+     * We can't drop the vnode lock, because that could result in a race.
+     * Sometimes, though, we get here and don't hold the vnode lock.
+     * I hate code paths that sometimes hold locks and sometimes don't.
+     * In any event, the dodge we use here is to check whether the vnode
+     * is locked, and if it isn't, then we gain and drop it around the call
+     * to vinvalbuf; otherwise, we leave it alone.
+     */
+    {
+	struct vnode *vp;
+	int iheldthelock;
+
+	vp = AFSTOV(tvc);
+#ifdef AFS_FBSD50_ENV
+	iheldthelock = VOP_ISLOCKED(vp, curthread);
+	if (!iheldthelock)
+	    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+	vinvalbuf(vp, V_SAVE, curthread->td_ucred, curthread, PINOD, 0);
+	if (!iheldthelock)
+	    VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
+#else
+	iheldthelock = VOP_ISLOCKED(vp, curproc);
+	if (!iheldthelock)
+	    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
+	vinvalbuf(vp, V_SAVE, curthread->td_ucred, curproc, PINOD, 0);
+	if (!iheldthelock)
+	    VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
+#endif
+    }
 #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	8 Oct 2003 05:09:43 -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
@@ -104,25 +106,41 @@
 osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
 {
     struct vattr tvattr;
+    struct vnode *vp;
     register afs_int32 code;
-    struct osi_stat tstat;
     AFS_STATCNT(osi_Truncate);
 
-    /* This routine only shrinks files, and most systems
+    MObtainWriteLock(&afs_xosi, 321);
+    vp = afile->vnode;
+    /*
+     * This routine only shrinks files, and most systems
      * have very slow truncates, even when the file is already
      * small enough.  Check now and save some time.
      */
-    code = afs_osi_Stat(afile, &tstat);
-    if (code || tstat.size <= asize)
-	return code;
-    MObtainWriteLock(&afs_xosi, 321);
+    AFS_GUNLOCK();
+#if defined(AFS_FBSD50_ENV)
+    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+    code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
+#else
+    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
+    code = VOP_GETATTR(afile->vnode, &tvattr, afs_osi_credp, curproc);
+#endif
+    if (code != 0 || tvattr.va_size <= asize)
+	goto out;
+
     VATTR_NULL(&tvattr);
     tvattr.va_size = asize;
-    AFS_GUNLOCK();
 #if defined(AFS_FBSD50_ENV)
-    code = VOP_SETATTR(afile->vnode, &tvattr, afs_osi_credp, curthread);
+    code = VOP_SETATTR(vp, &tvattr, afs_osi_credp, curthread);
+#else
+    code = VOP_SETATTR(vp, &tvattr, afs_osi_credp, curproc);
+#endif
+
+out:
+#if defined(AFS_FBSD50_ENV)
+    VOP_UNLOCK(vp, LK_EXCLUSIVE, curthread);
 #else
-    code = VOP_SETATTR(afile->vnode, &tvattr, afs_osi_credp, curproc);
+    VOP_UNLOCK(vp, LK_EXCLUSIVE, curproc);
 #endif
     AFS_GLOCK();
     MReleaseWriteLock(&afs_xosi);
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	8 Oct 2003 05:09:43 -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	8 Oct 2003 05:09:43 -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	8 Oct 2003 05:09:43 -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	8 Oct 2003 05:09:43 -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	8 Oct 2003 05:09:43 -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	8 Oct 2003 05:09:43 -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;
@@ -114,10 +112,10 @@
     register struct vcache *tvp = 0;
 #ifdef AFS_FBSD50_ENV
     struct thread *td = curthread;
-    struct ucred cr = *td->td_ucred;
+    struct ucred *cr = crhold(td->td_ucred);
 #else
     struct proc *p = curproc;
-    struct ucred cr = *p->p_cred->pc_ucred;
+    struct ucred *cr = crhold(p->p_cred->pc_ucred);
 #endif
 
     AFS_GLOCK();
@@ -126,12 +124,14 @@
 	tvp = afs_globalVp;
 	error = 0;
     } else {
+tryagain:
 	if (afs_globalVp) {
 	    afs_PutVCache(afs_globalVp);
+	    /* vrele() needed here or not? */
 	    afs_globalVp = NULL;
 	}
 
-	if (!(error = afs_InitReq(&treq, &cr)) && !(error = afs_CheckInit())) {
+	if (!(error = afs_InitReq(&treq, cr)) && !(error = afs_CheckInit())) {
 	    tvp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
 	    /* we really want this to stay around */
 	    if (tvp)
@@ -141,34 +141,41 @@
 	}
     }
     if (tvp) {
-	osi_vnhold(tvp, 0);
+	struct vnode *vp = AFSTOV(tvp);
+
+	ASSERT_VI_UNLOCKED(vp, "afs_root");
 	AFS_GUNLOCK();
+	/*
+	 * I'm uncomfortable about this.  Shouldn't this happen at a
+	 * higher level, and shouldn't we busy the top-level directory
+	 * to prevent recycling?
+	 */
 #ifdef AFS_FBSD50_ENV
-	vn_lock(AFSTOV(tvp), LK_EXCLUSIVE | LK_RETRY, td);
+	error = vget(vp, LK_EXCLUSIVE | LK_RETRY, td);
+	vp->v_vflag |= VV_ROOT;
 #else
-	vn_lock(AFSTOV(tvp), LK_EXCLUSIVE | LK_RETRY, p);
+	error = vget(vp, LK_EXCLUSIVE | LK_RETRY, p);
+	vp->v_flag |= VROOT;
 #endif
 	AFS_GLOCK();
+	if (error != 0)
+		goto tryagain;
+
 	afs_globalVFS = mp;
-	*vpp = AFSTOV(tvp);
-	tvp->v.v_flag |= VROOT;
+	*vpp = vp;
     }
 
     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *vpp,
 	       ICL_TYPE_INT32, error);
     AFS_GUNLOCK();
+    crfree(cr);
     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 +187,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 +224,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 +243,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 +255,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	8 Oct 2003 05:09:43 -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,12 @@
     struct vm_object *obj;
 
     vp = AFSTOV(avc);
-    simple_lock(&vp->v_interlock);
+    ASSERT_VOP_LOCKED(vp, __func__);
     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);
     /*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	8 Oct 2003 05:09:44 -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 *);
@@ -59,7 +107,7 @@
 /* Global vfs data structures for AFS. */
 vop_t **afs_vnodeop_p;
 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
-    {&vop_default_desc, (vop_t *) vop_eopnotsupp},
+    {&vop_default_desc, (vop_t *) vop_defaultop},
     {&vop_access_desc, (vop_t *) afs_vop_access},	/* access */
     {&vop_advlock_desc, (vop_t *) afs_vop_advlock},	/* advlock */
     {&vop_bmap_desc, (vop_t *) afs_vop_bmap},	/* bmap */
@@ -76,10 +124,8 @@
     {&vop_getvobject_desc, (vop_t *) vop_stdgetvobject},
     {&vop_putpages_desc, (vop_t *) afs_vop_putpages},	/* write */
     {&vop_inactive_desc, (vop_t *) afs_vop_inactive},	/* inactive */
-    {&vop_islocked_desc, (vop_t *) afs_vop_islocked},	/* islocked */
     {&vop_lease_desc, (vop_t *) vop_null},
     {&vop_link_desc, (vop_t *) afs_vop_link},	/* link */
-    {&vop_lock_desc, (vop_t *) afs_vop_lock},	/* lock */
     {&vop_lookup_desc, (vop_t *) afs_vop_lookup},	/* lookup */
     {&vop_mkdir_desc, (vop_t *) afs_vop_mkdir},	/* mkdir */
     {&vop_mknod_desc, (vop_t *) afs_vop_mknod},	/* mknod */
@@ -87,6 +133,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 */
@@ -99,7 +146,6 @@
     {&vop_setattr_desc, (vop_t *) afs_vop_setattr},	/* setattr */
     {&vop_strategy_desc, (vop_t *) afs_vop_strategy},	/* strategy */
     {&vop_symlink_desc, (vop_t *) afs_vop_symlink},	/* symlink */
-    {&vop_unlock_desc, (vop_t *) afs_vop_unlock},	/* unlock */
     {&vop_write_desc, (vop_t *) afs_vop_write},	/* write */
     {&vop_ioctl_desc, (vop_t *) afs_vop_ioctl},	/* XXX ioctl */
     /*{ &vop_seek_desc, afs_vop_seek }, *//* seek */
@@ -122,7 +168,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 +534,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 +551,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 +574,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 +585,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 +616,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 +626,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 +695,10 @@
 	    }
 	}
     }
+#ifdef AFS_FBSD50_ENV
+    vm_page_unlock_queues();
+    VM_OBJECT_UNLOCK(object);
+#endif
     return 0;
 }
 
@@ -543,16 +723,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 +746,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 +798,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];
 }
@@ -933,26 +1131,44 @@
     return error;
 }
 
+/* struct vop_symlink_args {
+ *	struct vnode *a_dvp;
+ *	struct vnode **a_vpp;
+ *	struct componentname *a_cnp;
+ *	struct vattr *a_vap;
+ *	char *a_target;
+ * };
+ */
 int
-afs_vop_symlink(ap)
-     struct vop_symlink_args	/* {
-				 * struct vnode *a_dvp;
-				 * struct vnode **a_vpp;
-				 * struct componentname *a_cnp;
-				 * struct vattr *a_vap;
-				 * char *a_target;
-				 * } */ *ap;
+afs_vop_symlink(struct vop_symlink_args *ap)
 {
-    register struct vnode *dvp = ap->a_dvp;
-    int error = 0;
-    /* NFS ignores a_vpp; so do we. */
+    struct vnode *dvp;
+    struct vnode *newvp;
+    struct vcache *vcp;
+    int error;
+
+    dvp = ap->a_dvp;
+    newvp = NULL;
+    error = 0;
 
     GETNAME();
     AFS_GLOCK();
     error =
 	afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
+    if (error == 0) {
+	error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
+	if (error == 0) {
+	    newvp = AFSTOV(vcp);
+#ifdef AFS_FBSD50_ENV
+	    vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_thread);
+#else
+	    vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc);
+#endif
+	}
+    }
     AFS_GUNLOCK();
     DROPNAME();
+    *(ap->a_vpp) = newvp;
     return error;
 }
 
@@ -1043,69 +1259,36 @@
     return 0;
 }
 
+/*
+ * struct vop_reclaim_args {
+ *	struct vnode *a_vp;
+ * };
+ */
 int
-afs_vop_reclaim(ap)
-     struct vop_reclaim_args	/* {
-				 * struct vnode *a_vp;
-				 * } */ *ap;
-{
-#ifdef AFS_DO_FLUSH_IN_RECLAIM
-    int error, sl;
-#endif
-    register struct vnode *vp = ap->a_vp;
-
-    cache_purge(vp);		/* just in case... */
-
-#ifdef AFS_DO_FLUSH_IN_RECLAIM
-    AFS_GLOCK();
-    error = afs_FlushVCache(VTOAFS(vp), &sl);	/* tosses our stuff from vnode */
-    AFS_GUNLOCK();
-    ubc_unlink(vp);
-    if (!error && vp->v_data)
-	panic("afs_reclaim: vnode not cleaned");
-    return error;
-#else
-    if (vp->v_usecount == 2) {
-	vprint("reclaim count==2", vp);
-    } else if (vp->v_usecount == 1) {
-	vprint("reclaim count==1", vp);
-    } else
-	vprint("reclaim bad count", vp);
-
-    return 0;
-#endif
-}
-
-int
-afs_vop_lock(ap)
-     struct vop_lock_args	/* {
-				 * struct vnode *a_vp;
-				 * } */ *ap;
-{
-    register struct vnode *vp = ap->a_vp;
-    register struct vcache *avc = VTOAFS(vp);
-
-#ifdef AFS_FBSD50_ENV
-    if (!strcmp(vp->v_tag, "none"))
-#else
-    if (vp->v_tag == VT_NON)
-#endif
-	return (ENOENT);
-    return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
-}
-
-int
-afs_vop_unlock(ap)
-     struct vop_unlock_args	/* {
-				 * struct vnode *a_vp;
-				 * } */ *ap;
+afs_vop_reclaim(struct vop_reclaim_args *ap)
 {
+    /* copied from ../OBSD/osi_vnodeops.c:afs_nbsd_reclaim() */
+    int code, slept;
     struct vnode *vp = ap->a_vp;
     struct vcache *avc = VTOAFS(vp);
-    return (lockmgr
-	    (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
-	     ap->a_p));
+    int haveGlock = ISAFS_GLOCK();
+    int haveVlock = CheckLock(&afs_xvcache);
 
+    if (!haveGlock)
+	AFS_GLOCK();
+    if (!haveVlock)
+	ObtainWriteLock(&afs_xvcache, 901);
+#ifndef AFS_DISCON_ENV
+    code = afs_FlushVCache(avc, &slept);	/* tosses our stuff from vnode */
+#else
+    /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */
+    code = afs_FlushVS(avc);
+#endif
+    if (!haveVlock)
+	ReleaseWriteLock(&afs_xvcache);
+    if (!haveGlock)
+	AFS_GUNLOCK();
+    return code;
 }
 
 int
@@ -1173,16 +1356,6 @@
 	   (s & CVFlushed) ? " flush in progress" : "");
     printf("\n");
     return 0;
-}
-
-int
-afs_vop_islocked(ap)
-     struct vop_islocked_args	/* {
-				 * struct vnode *a_vp;
-				 * } */ *ap;
-{
-    struct vcache *vc = VTOAFS(ap->a_vp);
-    return lockstatus(&vc->rwlock, ap->a_p);
 }
 
 /*
Index: src/cf/osconf.m4
===================================================================
RCS file: /cvs/openafs/src/cf/osconf.m4,v
retrieving revision 1.39
diff -u -r1.39 osconf.m4
--- src/cf/osconf.m4	1 Jul 2003 19:30:30 -0000	1.39
+++ src/cf/osconf.m4	8 Oct 2003 05:09:47 -0000
@@ -191,7 +191,7 @@
 		SHLIB_LDFLAGS="-shared -Xlinker -x"
 		TXLIBS="-lncurses"
 		XCFLAGS="-O2 -pipe"
-		XLIBS="${LIB_AFSDB} -lcompat"
+		XLIBS="${LIB_AFSDB}"
 		YACC="byacc"
 		;;
 
@@ -203,7 +203,7 @@
 		SHLIB_LDFLAGS="-shared -Xlinker -x"
 		TXLIBS="-lncurses"
 		XCFLAGS="-O2 -pipe"
-		XLIBS="${LIB_AFSDB} -lcompat"
+		XLIBS="${LIB_AFSDB}"
 		YACC="byacc"
 		;;
 
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	8 Oct 2003 05:09:48 -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	8 Oct 2003 05:09:48 -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	8 Oct 2003 05:09:48 -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	8 Oct 2003 05:09:48 -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	8 Oct 2003 05:09:48 -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	8 Oct 2003 05:09:48 -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	8 Oct 2003 05:09:49 -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	8 Oct 2003 05:09:49 -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	8 Oct 2003 05:09:51 -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	8 Oct 2003 05:09:51 -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	8 Oct 2003 05:09:53 -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	8 Oct 2003 05:09:53 -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	8 Oct 2003 05:09:54 -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	8 Oct 2003 05:09:56 -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/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	8 Oct 2003 05:10:02 -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	8 Oct 2003 05:10:05 -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) {