diff -Naur openafs_1.4.14.orig/acinclude.m4 openafs_1.4.14/acinclude.m4
--- openafs_1.4.14.orig/acinclude.m4	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/acinclude.m4	2011-03-29 08:33:49.040187976 +0200
@@ -749,6 +749,7 @@
 		 LINUX_FS_STRUCT_SUPER_HAS_ALLOC_INODE
 		 LINUX_FS_STRUCT_SUPER_HAS_EVICT_INODE
 		 LINUX_FS_STRUCT_SUPER_BLOCK_HAS_S_BDI
+		 AC_CHECK_LINUX_STRUCT([super_block], [s_d_op], [fs.h])
 		 LINUX_STRUCT_BDI_HAS_NAME
 	         LINUX_FS_STRUCT_ADDRESS_SPACE_HAS_PAGE_LOCK
 	         LINUX_FS_STRUCT_ADDRESS_SPACE_HAS_GFP_MASK
@@ -768,6 +769,7 @@
 	  	 LINUX_WRITE_INODE_RETURN_TYPE
 	  	 LINUX_IOP_I_CREATE_TAKES_NAMEIDATA
 	  	 LINUX_IOP_I_LOOKUP_TAKES_NAMEIDATA
+		 LINUX_IOP_I_PERMISSION_TAKES_FLAGS
 	  	 LINUX_IOP_I_PERMISSION_TAKES_NAMEIDATA
 	  	 LINUX_IOP_I_PUT_LINK_TAKES_COOKIE
 	  	 LINUX_DOP_D_REVALIDATE_TAKES_NAMEIDATA
@@ -815,6 +817,8 @@
 		 LINUX_GENERIC_FILE_AIO_READ
 		 LINUX_INIT_WORK_HAS_DATA
 		 LINUX_REGISTER_SYSCTL_TABLE_NOFLAG
+		 LINUX_HAVE_DCACHE_LOCK
+		 LINUX_D_COUNT_IS_INT
 		 LINUX_SYSCTL_TABLE_CHECKING
 		 LINUX_STRUCT_CTL_TABLE_HAS_CTL_NAME
 		 LINUX_HAVE_IGET
diff -Naur openafs_1.4.14.orig/configure.in openafs_1.4.14/configure.in
--- openafs_1.4.14.orig/configure.in	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/configure.in	2011-03-29 08:33:49.039188017 +0200
@@ -108,12 +108,6 @@
 src/mpp/Makefile \
 src/null/Makefile \
 src/package/Makefile \
-src/packaging/MacOS/OpenAFS-debug.Description.plist \
-src/packaging/MacOS/OpenAFS-debug.Info.plist \
-src/packaging/MacOS/OpenAFS.Description.plist \
-src/packaging/MacOS/OpenAFS.Info.plist \
-src/packaging/MacOS/OpenAFS.info \
-src/packaging/MacOS/buildpkg.sh \
 src/packaging/RedHat/openafs.spec \
 src/pam/Makefile \
 src/pinstall/Makefile \
diff -Naur openafs_1.4.14.orig/src/afs/afs_daemons.c openafs_1.4.14/src/afs/afs_daemons.c
--- openafs_1.4.14.orig/src/afs/afs_daemons.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/afs_daemons.c	2011-03-29 08:33:49.174182467 +0200
@@ -376,7 +376,11 @@
 		    dp = d_find_alias(AFSTOV(afs_globalVp));
 		    
 #if defined(AFS_LINUX24_ENV)
+#if defined(HAVE_DCACHE_LOCK)
 		    spin_lock(&dcache_lock);
+#else
+		    spin_lock(&AFSTOV(vcp)->i_lock);
+#endif
 #if defined(AFS_LINUX26_ENV)
 		    spin_lock(&dp->d_lock);
 #endif
@@ -388,7 +392,11 @@
 #if defined(AFS_LINUX26_ENV)
 		    spin_unlock(&dp->d_lock);
 #endif
+#if defined(HAVE_DCACHE_LOCK)
 		    spin_unlock(&dcache_lock);
+#else
+		    spin_unlock(&AFSTOV(vcp)->i_lock);
+#endif
 #endif
 		    dput(dp);
 		    
diff -Naur openafs_1.4.14.orig/src/afs/afs.h openafs_1.4.14/src/afs/afs.h
--- openafs_1.4.14.orig/src/afs/afs.h	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/afs.h	2011-03-29 08:33:49.171182590 +0200
@@ -75,7 +75,7 @@
 #define	PIGGYSIZE	1350	/* max piggyback size */
 #define	MAXVOLS		128	/* max vols we can store */
 #define	MAXSYSNAME	128	/* max sysname (i.e. @sys) size */
-#define MAXNUMSYSNAMES	16	/* max that current constants allow */
+#define MAXNUMSYSNAMES	32	/* max that current constants allow */
 #define	NOTOKTIMEOUT	(2*3600)	/* time after which to timeout conns sans tokens */
 #define	NOPAG		0xffffffff
 #define AFS_NCBRS	300	/* max # of call back return entries */
diff -Naur openafs_1.4.14.orig/src/afs/afs_vcache.c openafs_1.4.14/src/afs/afs_vcache.c
--- openafs_1.4.14.orig/src/afs/afs_vcache.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/afs_vcache.c	2011-03-29 08:33:49.170182631 +0200
@@ -673,12 +673,15 @@
 #if defined(AFS_LINUX22_ENV)
 	    if (tvc != afs_globalVp && VREFCOUNT(tvc) > 1 && tvc->opens == 0) {
                 struct dentry *dentry;
+		struct inode *inode = AFSTOV(tvc);
                 struct list_head *cur, *head;
                 AFS_GUNLOCK();
+
+#if defined(HAVE_DCACHE_LOCK)
 #if defined(AFS_LINUX24_ENV)
                 spin_lock(&dcache_lock);
 #endif
-		head = &(AFSTOV(tvc))->i_dentry;
+		head = &inode->i_dentry;
 
 restart:
                 cur = head;
@@ -687,7 +690,6 @@
 
 		    if (d_unhashed(dentry))
 			continue;
-
 		    dget_locked(dentry);
 
 #if defined(AFS_LINUX24_ENV)
@@ -707,6 +709,35 @@
 #if defined(AFS_LINUX24_ENV)
 		spin_unlock(&dcache_lock);
 #endif
+#else /* HAVE_DCACHE_LOCK */
+		spin_lock(&inode->i_lock);
+		head = &inode->i_dentry;
+
+restart:
+		cur = head;
+		while ((cur = cur->next) != head) {
+		    dentry = list_entry(cur, struct dentry, d_alias);
+
+		    spin_lock(&dentry->d_lock);
+		    if (d_unhashed(dentry)) {
+			spin_unlock(&dentry->d_lock);
+			continue;
+		    }
+		    spin_unlock(&dentry->d_lock);
+		    dget(dentry);
+
+		    spin_unlock(&inode->i_lock);
+		    if (d_invalidate(dentry) == -EBUSY) {
+			dput(dentry);
+			/* perhaps lock and try to continue? (use cur as head?) */
+			goto inuse;
+		    }
+		    dput(dentry);
+		    spin_lock(&inode->i_lock);
+		    goto restart;
+		}
+		spin_unlock(&inode->i_lock);
+#endif /* HAVE_DCACHE_LOCK */
 	    inuse:
 		AFS_GLOCK();
 	    }
diff -Naur openafs_1.4.14.orig/src/afs/LINUX/osi_compat.h openafs_1.4.14/src/afs/LINUX/osi_compat.h
--- openafs_1.4.14.orig/src/afs/LINUX/osi_compat.h	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/LINUX/osi_compat.h	2011-03-29 08:33:49.171182590 +0200
@@ -135,7 +135,6 @@
 #else
 #define KALLOC_TYPE GFP_KERNEL
 #endif
-
 #endif
 
 static inline int
diff -Naur openafs_1.4.14.orig/src/afs/LINUX/osi_groups.c openafs_1.4.14/src/afs/LINUX/osi_groups.c
--- openafs_1.4.14.orig/src/afs/LINUX/osi_groups.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/LINUX/osi_groups.c	2011-03-29 08:33:49.171182590 +0200
@@ -230,7 +230,7 @@
 {
     struct key *old;
     char desc[20];
-    unsigned long not_in_quota;
+    unsigned long flags;
     int code = -EINVAL;
 
     if (!__key_type_keyring)
@@ -239,24 +239,31 @@
     if (!keyring) {
 
 	/* create an empty session keyring */
-	not_in_quota = KEY_ALLOC_IN_QUOTA;
 	sprintf(desc, "_ses.%u", current->tgid);
 
+	/* if we're root, don't count the keyring against our quota. This
+	 * avoids starvation issues when dealing with PAM modules that always
+	 * setpag() as root */
+	if (current_uid() == 0)
+	    flags = KEY_ALLOC_NOT_IN_QUOTA;
+	else
+	    flags = KEY_ALLOC_IN_QUOTA;
+
 #if defined(KEY_ALLOC_NEEDS_STRUCT_TASK)
 	keyring = key_alloc(__key_type_keyring, desc,
 			    current_uid(), current_gid(), current,
 			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
-			    not_in_quota);
+			    flags);
 #elif defined(KEY_ALLOC_NEEDS_CRED)
 	keyring = key_alloc(__key_type_keyring, desc,
 			    current_uid(), current_gid(), current_cred(),
 			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
-			    not_in_quota);
+			    flags);
 #else
 	keyring = key_alloc(__key_type_keyring, desc,
 			    current_uid(), current_gid(),
 			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
-			    not_in_quota);
+			    flags);
 #endif
 	if (IS_ERR(keyring)) {
 	    code = PTR_ERR(keyring);
@@ -338,9 +345,9 @@
 #ifdef LINUX_KEYRING_SUPPORT
     if (code == 0) {
 
-	(void) install_session_keyring(NULL);
+	code = install_session_keyring(NULL);
 
-	if (current_session_keyring()) {
+	if (code == 0 && current_session_keyring()) {
 	    struct key *key;
 	    key_perm_t perm;
 
@@ -348,17 +355,22 @@
 	    perm |= KEY_USR_VIEW | KEY_USR_SEARCH;
 
 #if defined(KEY_ALLOC_NEEDS_STRUCT_TASK)
-	    key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, current, perm, 1);
+	    key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, current,
+			    perm, KEY_ALLOC_NOT_IN_QUOTA);
 #elif defined(KEY_ALLOC_NEEDS_CRED)
-	    key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, current_cred(), perm, 1);
+	    key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, current_cred(),
+			    perm, KEY_ALLOC_NOT_IN_QUOTA);
 #else
-	    key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, perm, 1);
+	    key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, perm,
+			    KEY_ALLOC_NOT_IN_QUOTA);
 #endif
 
 	    if (!IS_ERR(key)) {
 		key_instantiate_and_link(key, (void *) newpag, sizeof(afs_uint32),
 					 current_session_keyring(), NULL);
 		key_put(key);
+	    } else {
+		code = PTR_ERR(key);
 	    }
 	}
     }
diff -Naur openafs_1.4.14.orig/src/afs/LINUX/osi_vfsops.c openafs_1.4.14/src/afs/LINUX/osi_vfsops.c
--- openafs_1.4.14.orig/src/afs/LINUX/osi_vfsops.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/LINUX/osi_vfsops.c	2011-03-29 08:33:49.172182549 +0200
@@ -140,6 +140,11 @@
     sb->s_blocksize_bits = 10;
     sb->s_magic = AFS_VFSMAGIC;
     sb->s_op = &afs_sops;	/* Super block (vfs) ops */
+
+#if defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
+    sb->s_d_op = &afs_dentry_operations;
+#endif
+
     /* used for inodes backing_dev_info field, also */
     afs_backing_dev_info = osi_Alloc(sizeof(struct backing_dev_info));
 #if defined(HAVE_BDI_INIT)
@@ -227,7 +232,9 @@
 #else
 		afsp->s_root = d_alloc_root(ip, NULL);
 #endif
+#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
 		afsp->s_root->d_op = &afs_dentry_operations;
+#endif
 	    } else
 		code = ENOENT;
 	}
diff -Naur openafs_1.4.14.orig/src/afs/LINUX/osi_vnodeops.c openafs_1.4.14/src/afs/LINUX/osi_vnodeops.c
--- openafs_1.4.14.orig/src/afs/LINUX/osi_vnodeops.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/LINUX/osi_vnodeops.c	2011-03-29 08:33:49.172182549 +0200
@@ -865,10 +865,16 @@
     int valid;
     struct afs_fakestat_state fakestate;
 
+#ifdef LOOKUP_RCU
+    /* We don't support RCU path walking */
+    if (nd->flags & LOOKUP_RCU)
+       return -ECHILD;
+#endif
 #ifdef AFS_LINUX24_ENV
     lock_kernel();
 #endif
     AFS_GLOCK();
+
     afs_InitFakeStat(&fakestate);
 
     if (dp->d_inode) {
@@ -1067,7 +1073,9 @@
 	afs_getattr(vcp, &vattr, credp);
 	afs_fill_inode(ip, &vattr);
 	insert_inode_hash(ip);
+#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
 	dp->d_op = &afs_dentry_operations;
+#endif
 	dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
 	d_instantiate(dp, ip);
     }
@@ -1123,7 +1131,9 @@
 	    )
 	    insert_inode_hash(ip);
     }
+#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
     dp->d_op = &afs_dentry_operations;
+#endif
     dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
     AFS_GUNLOCK();
 
@@ -1315,7 +1325,9 @@
 	afs_getattr(tvcp, &vattr, credp);
 	afs_fill_inode(ip, &vattr);
 
+#if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
 	dp->d_op = &afs_dentry_operations;
+#endif
 	dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
 	d_instantiate(dp, ip);
     }
@@ -1384,9 +1396,18 @@
 #endif
 
 #if defined(AFS_LINUX24_ENV)
+#if defined(D_COUNT_INT)
+    spin_lock(&olddp->d_lock);
+    if (olddp->d_count > 1) {
+	spin_unlock(&olddp->d_lock);
+	shrink_dcache_parent(olddp);
+    } else
+	spin_unlock(&olddp->d_lock);
+#else
     if (atomic_read(&olddp->d_count) > 1)
 	shrink_dcache_parent(olddp);
 #endif
+#endif
 
     AFS_GLOCK();
     code = afs_rename(VTOAFS(oldip), oldname, VTOAFS(newip), newname, credp);
@@ -1786,16 +1807,25 @@
  * Check access rights - returns error if can't check or permission denied.
  */
 static int
-#ifdef IOP_PERMISSION_TAKES_NAMEIDATA
+#if defined(IOP_PERMISSION_TAKES_FLAGS)
+afs_linux_permission(struct inode *ip, int mode, unsigned int flags)
+#elif defined(IOP_PERMISSION_TAKES_NAMEIDATA)
 afs_linux_permission(struct inode *ip, int mode, struct nameidata *nd)
 #else
 afs_linux_permission(struct inode *ip, int mode)
 #endif
 {
     int code;
-    cred_t *credp = crref();
+    cred_t *credp;
     int tmp = 0;
 
+#if defined(IOP_PERMISSION_TAKES_FLAGS)
+    /* We don't support RCU path walking */
+    if (flags & IPERM_FLAG_RCU)
+       return -ECHILD;
+#endif
+
+    credp = crref();
     AFS_GLOCK();
     if (mode & MAY_EXEC)
 	tmp |= VEXEC;
diff -Naur openafs_1.4.14.orig/src/afs/Makefile.in openafs_1.4.14/src/afs/Makefile.in
--- openafs_1.4.14.orig/src/afs/Makefile.in	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/Makefile.in	2011-03-29 08:33:49.180182219 +0200
@@ -13,7 +13,7 @@
 all: depinstall
 
 depinstall: ${TOP_INCDIR}/afs/afs.h ${TOP_INCDIR}/afs/osi_inode.h ${TOP_INCDIR}/afs/afs_stats.h \
-	${TOP_INCDIR}/afs/exporter.h ${TOP_INCDIR}/afs/nfsclient.h afszcm.cat AFS_component_version_number.c ${TOP_INCDIR}/afs/unified_afs.h ${TOP_INCDIR}/afs/sysctl.h
+	${TOP_INCDIR}/afs/exporter.h ${TOP_INCDIR}/afs/nfsclient.h afszcm.cat AFS_component_version_number.c ${TOP_INCDIR}/afs/unified_afs.h
 
 afs_trace.h afs_trace.msf: afs_trace.et
 	${COMPILE_ET} -v 2 -p ${srcdir} afs_trace.et
@@ -39,7 +39,7 @@
 			gencat afszcm.cat afs_trace.msf ;; \
 	esac
 
-install:   ${DESTDIR}${includedir}/afs/afs.h  ${DESTDIR}${includedir}/afs/osi_inode.h ${DESTDIR}${includedir}/afs/afs_stats.h ${DESTDIR}${includedir}/afs/exporter.h ${DESTDIR}${includedir}/afs/nfsclient.h ${DESTDIR}${includedir}/afs/unified_afs.h ${DESTDIR}${includedir}/afs/sysctl.h
+install:   ${DESTDIR}${includedir}/afs/afs.h  ${DESTDIR}${includedir}/afs/osi_inode.h ${DESTDIR}${includedir}/afs/afs_stats.h ${DESTDIR}${includedir}/afs/exporter.h ${DESTDIR}${includedir}/afs/nfsclient.h ${DESTDIR}${includedir}/afs/unified_afs.h
 	case ${SYS_NAME} in \
 		*linux* ) \
 			${INSTALL} ${MKAFS_OSTYPE}/osi_vfs.h ${DESTDIR}${includedir}/afs || true ;;\
@@ -123,7 +123,7 @@
 	${INSTALL} $? $@
 
 
-dest:   ${DEST}/include/afs/afs.h ${DEST}/include/afs/osi_inode.h ${DEST}/include/afs/afs_stats.h ${DEST}/include/afs/exporter.h ${DEST}/include/afs/nfsclient.h ${DEST}/include/afs/unified_afs.h ${DEST}/include/afs/sysctl.h
+dest:   ${DEST}/include/afs/afs.h ${DEST}/include/afs/osi_inode.h ${DEST}/include/afs/afs_stats.h ${DEST}/include/afs/exporter.h ${DEST}/include/afs/nfsclient.h ${DEST}/include/afs/unified_afs.h
 	case ${SYS_NAME} in \
 		i386_fbsd* ) \
 			echo skipping afszcm.cat install for ${SYS_NAME} ;; \
diff -Naur openafs_1.4.14.orig/src/afs/sysincludes.h openafs_1.4.14/src/afs/sysincludes.h
--- openafs_1.4.14.orig/src/afs/sysincludes.h	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/sysincludes.h	2011-03-29 08:33:49.174182467 +0200
@@ -79,7 +79,10 @@
 #include <linux/key-type.h>
 #endif
 #ifndef KEY_ALLOC_IN_QUOTA
-#define KEY_ALLOC_IN_QUOTA 1
+/* Before these flags were added in Linux commit v2.6.18-rc1~816,
+ * key_alloc just took a boolean not_in_quota */
+#define KEY_ALLOC_IN_QUOTA 0
+#define KEY_ALLOC_NOT_IN_QUOTA 1
 #endif
 #endif
 #endif
diff -Naur openafs_1.4.14.orig/src/afs/VNOPS/afs_vnop_flock.c openafs_1.4.14/src/afs/VNOPS/afs_vnop_flock.c
--- openafs_1.4.14.orig/src/afs/VNOPS/afs_vnop_flock.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/afs/VNOPS/afs_vnop_flock.c	2011-03-29 08:33:49.177182342 +0200
@@ -539,24 +539,8 @@
 #else
 	) {
 #endif
-    /* this next check is safer when left out, but more applications work
-     * with it in.  However, they fail in race conditions.  The question is
-     * what to do for people who don't have source to their application;
-     * this way at least, they can get work done */
-#ifdef AFS_LINUX24_ENV
-    if (af->l_len == OFFSET_MAX)
-	af->l_len = 0;		/* since some systems indicate it as EOF */
-#else
-    if (af->l_len == 0x7fffffff)
-	af->l_len = 0;		/* since some systems indicate it as EOF */
-#ifdef AFS_LINUX_64BIT_KERNEL
-    if (af->l_len == LONG_MAX)
-	af->l_len = 0;		/* since some systems indicate it as EOF */
-#endif
-#endif
-    /* Java VMs ask for l_len=(long)-1 regardless of OS/CPU; bottom 32 bits
-     * sometimes get masked off by OS */
-    if ((sizeof(af->l_len) == 8) && (af->l_len == 0x7ffffffffffffffe))
+    /* Java VMs ask for l_len=(long)-1 regardless of OS/CPU */
+    if ((sizeof(af->l_len) == 8) && (af->l_len == 0x7fffffffffffffffLL))
 	af->l_len = 0;
     /* next line makes byte range locks always succeed,
      * even when they should block */
diff -Naur openafs_1.4.14.orig/src/bozo/bosoprocs.c openafs_1.4.14/src/bozo/bosoprocs.c
--- openafs_1.4.14.orig/src/bozo/bosoprocs.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/bozo/bosoprocs.c	2011-03-29 08:33:49.123184563 +0200
@@ -1315,7 +1315,7 @@
 
 struct bozo_bosEntryStats bozo_bosEntryStats[] = {
     {NULL, 1, 1, 0755, 02},	/* AFSDIR_SERVER_AFS_DIRPATH    */
-    {NULL, 1, 1, 0755, 02},	/* AFSDIR_SERVER_ETC_DIRPATH    */
+    {NULL, 1, 1, 0700, 02},	/* AFSDIR_SERVER_ETC_DIRPATH    */
     {NULL, 1, 1, 0755, 02},	/* AFSDIR_SERVER_BIN_DIRPATH    */
     {NULL, 1, 1, 0755, 02},	/* AFSDIR_SERVER_LOGS_DIRPATH   */
     {NULL, 1, 0, 0700, 07},	/* AFSDIR_SERVER_BACKUP_DIRPATH */
diff -Naur openafs_1.4.14.orig/src/cf/linux-test1.m4 openafs_1.4.14/src/cf/linux-test1.m4
--- openafs_1.4.14.orig/src/cf/linux-test1.m4	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/cf/linux-test1.m4	2011-03-29 08:33:49.219180616 +0200
@@ -84,3 +84,28 @@
     ac_linux_kbuild_requires_extra_cflags=yes)
     CPPFLAGS="$save_CPPFLAGS"
     AC_MSG_RESULT($ac_linux_kbuild_requires_extra_cflags)])
+
+dnl AC_CHECK_LINUX_BUILD([msg], [var], [includes], [code], [define], [CFLAGS])
+AC_DEFUN([AC_CHECK_LINUX_BUILD],
+ [AS_VAR_PUSHDEF([ac_linux_build], [$2])dnl
+  AC_CACHE_CHECK([$1], [ac_linux_build],
+   [save_CPPFLAGS="$CPPFLAGS"
+     CPPFLAGS="$CPPFLAGS $7"
+     AC_TRY_KBUILD([$3], [$4],
+		  AS_VAR_SET([ac_linux_build], [yes]),
+		  AS_VAR_SET([ac_linux_build], [no]))
+     CPPFLAGS="$save_CPPFLAGS"
+   ])
+  AS_IF([test AS_VAR_GET([ac_linux_build]) = yes],
+        [AC_DEFINE([$5],1,[$6])])
+ ])
+
+dnl AC_CHECK_LINUX_STRUCT([structure], [element], [includes])
+AC_DEFUN([AC_CHECK_LINUX_STRUCT],
+ [AC_CHECK_LINUX_BUILD([for $2 in struct $1],
+		       [ac_cv_linux_struct_$1_has_$2],
+		       [#include <linux/$3>],
+		       [struct $1 _test; printk("%x\n", &_test.$2); ],
+		       AS_TR_CPP(STRUCT_$1_HAS_$2),
+		       [Define if kernel struct $1 has the $2 element])
+ ])
diff -Naur openafs_1.4.14.orig/src/cf/linux-test4.m4 openafs_1.4.14/src/cf/linux-test4.m4
--- openafs_1.4.14.orig/src/cf/linux-test4.m4	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/cf/linux-test4.m4	2011-03-29 08:33:49.220180575 +0200
@@ -675,18 +675,30 @@
 
 
 AC_DEFUN([LINUX_IOP_I_PERMISSION_TAKES_NAMEIDATA], [
-  AC_MSG_CHECKING([whether inode_operations.permission takes a nameidata])
-  AC_CACHE_VAL([ac_cv_linux_func_i_permission_takes_nameidata], [
-    AC_TRY_KBUILD(
+  AC_CHECK_LINUX_BUILD([whether inode_operations.permission takes a nameidata],
+		       [ac_cv_linux_func_i_permission_takes_nameidata],
 [#include <linux/fs.h>
 #include <linux/namei.h>],
 [struct inode _inode;
-struct dentry _dentry;
 struct nameidata _nameidata;
 (void)_inode.i_op->permission(&_inode, 0, &_nameidata);],
-      ac_cv_linux_func_i_permission_takes_nameidata=yes,
-      ac_cv_linux_func_i_permission_takes_nameidata=no)])
-  AC_MSG_RESULT($ac_cv_linux_func_i_permission_takes_nameidata)])
+		       [IOP_PERMISSION_TAKES_NAMEIDATA],
+		       [define if your iops.permission takes a nameidata argument],
+		       [-Werror])
+])
+
+
+AC_DEFUN([LINUX_IOP_I_PERMISSION_TAKES_FLAGS], [
+  AC_CHECK_LINUX_BUILD([whether inode_operations.permission takes flags],
+			[ac_cv_linux_func_i_permission_takes_flags],
+			[#include <linux/fs.h>],
+			[struct inode _inode;
+			unsigned int flags = 0;
+			(void)_inode.i_op->permission(&_inode, 0, flags);],
+		       [IOP_PERMISSION_TAKES_FLAGS],
+		       [define if your iops.permission takes a flags argument],
+		       [-Werror])
+])
 
 
 AC_DEFUN([LINUX_IOP_I_PUT_LINK_TAKES_COOKIE], [
@@ -1304,3 +1316,26 @@
   if test "x$ac_cv_linux_inode_setattr" = "xyes"; then
     AC_DEFINE([HAVE_LINUX_INODE_SETATTR], 1, [define if your kernel has inode_setattr()])
   fi])
+
+AC_DEFUN([LINUX_HAVE_DCACHE_LOCK], [
+  AC_CHECK_LINUX_BUILD([for dcache_lock],
+			[ac_cv_linux_have_dcache_lock],
+			[#include <linux/dcache.h> ],
+			[printk("%p", &dcache_lock);],
+			[HAVE_DCACHE_LOCK],
+			[define if dcache_lock exists],
+			[])
+])
+
+
+AC_DEFUN([LINUX_D_COUNT_IS_INT], [
+  AC_CHECK_LINUX_BUILD([if dentry->d_count is an int],
+			[ac_cv_linux_d_count_int],
+			[#include <linux/dcache.h> ],
+			[struct dentry _d;
+			dget(&_d);
+			_d.d_count = 1;],
+			[D_COUNT_INT],
+			[define if dentry->d_count is an int],
+			[-Werror])
+])
diff -Naur openafs_1.4.14.orig/src/cf/osconf.m4 openafs_1.4.14/src/cf/osconf.m4
--- openafs_1.4.14.orig/src/cf/osconf.m4	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/cf/osconf.m4	2011-03-29 08:33:49.220180575 +0200
@@ -4,9 +4,8 @@
 dnl defaults, override in case below as needed
 XCFLAGS='${DBG} ${OPTMZ}'
 SHLIB_SUFFIX="so"
-CC="cc"
-CCOBJ="cc"
-MT_CC="cc"
+CCOBJ=$CC
+MT_CC=$CC
 XLIBS="${LIB_AFSDB} ${XBSA_XLIBS}"
 
 dnl debugging and optimization flag defaults
@@ -350,9 +349,8 @@
 		;;
 
 	i386_umlinux22)
-		CC="gcc -pipe"
-		CCOBJ="gcc -pipe"
-		MT_CC="gcc -pipe"
+		CCOBJ="${CC} -pipe"
+		MT_CC="${CC} -pipe"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
 		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
@@ -367,9 +365,8 @@
 		;;
 
 	i386_linux*)
-		CC="gcc -pipe"
-		CCOBJ="gcc -pipe"
-		MT_CC="gcc -pipe"
+		CCOBJ="${CC} -pipe"
+		MT_CC="${CC} -pipe"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
 		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
@@ -388,9 +385,8 @@
 		;;
 
 	i386_umlinux24)
-		CC="gcc -pipe"
-		CCOBJ="gcc -pipe"
-		MT_CC="gcc -pipe"
+		CCOBJ="${CC} -pipe"
+		MT_CC="${CC} -pipe"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
 		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
@@ -409,9 +405,8 @@
 		;;
 
 	i386_umlinux26)
-		CC="gcc -pipe"
-		CCOBJ="gcc -pipe"
-		MT_CC="gcc -pipe"
+		CCOBJ="${CC} -pipe"
+		MT_CC="${CC} -pipe"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
 		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
@@ -665,8 +660,7 @@
 		;;
 
 	s390_linux22)
-		CC="gcc"
-		CCOBJ="gcc"
+		CCOBJ="$CC"
 		LD="ld"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
@@ -683,8 +677,7 @@
 		;;
 
 	s390_linux24|s390_linux26)
-		CC="gcc"
-		CCOBJ="gcc"
+		CCOBJ="$CC"
 		LD="ld"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
@@ -701,8 +694,7 @@
 		;;
 
 	s390x_linux24|s390x_linux26)
-		CC="gcc"
-		CCOBJ="gcc -fPIC"
+		CCOBJ="$CC -fPIC"
 		LD="ld"
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
@@ -780,7 +772,7 @@
 		SHLIB_LINKER="${CC} -shared"
 		;;
 
-	sparc64_linux*)
+	sparc*_linux*)
 		KERN_OPTMZ=-O2
 		LEX="flex -l"
 		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
@@ -795,20 +787,6 @@
 		YACC="bison -y"
 		SHLIB_LINKER="${MT_CC} -shared"
 		;;
-
-	sparc_linux22)
-		KERN_OPTMZ=-O2
-		LEX="flex -l"
-		MT_CFLAGS='-DAFS_PTHREAD_ENV -pthread -D_REENTRANT ${XCFLAGS}'
-		MT_LIBS="-lpthread"
-		PAM_CFLAGS="-O2 -Dlinux -DLINUX_PAM -fPIC"
-		SHLIB_CFLAGS="-fPIC"
-		SHLIB_LDFLAGS="-shared -Xlinker -x"
-		TXLIBS="-lncurses"
-		XCFLAGS="-O2 -D_LARGEFILE64_SOURCE"
-		YACC="bison -y"
-		SHLIB_LINKER="${MT_CC} -shared"
-		;;
 
 	sun4_413)
 		CCXPG2="/usr/xpg2bin/cc"
diff -Naur openafs_1.4.14.orig/src/ptserver/db_verify.c openafs_1.4.14/src/ptserver/db_verify.c
--- openafs_1.4.14.orig/src/ptserver/db_verify.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/ptserver/db_verify.c	2011-03-29 08:33:49.217180698 +0200
@@ -1179,9 +1179,6 @@
 	    if ((id < 0) && (flags & PRGRP)) {
 		int count = 0;
 		afs_int32 na;
-#if defined(SUPERGROUPS)
-		afs_int32 ng;
-#endif
 		int i;
 		for (i = 0; i < PRSIZE; i++) {
 		    afs_int32 uid = ntohl(e.entries[i]);
@@ -1200,43 +1197,6 @@
 				id);
 #endif
 		}
-#if defined(SUPERGROUPS)
-#define g	(*((struct prentryg *)&e))
-		ng = ntohl(g.nextsg);
-		for (i = 0; i < SGSIZE; i++) {
-		    afs_int32 uid = ntohl(g.supergroup[i]);
-		    if (uid == 0)
-			break;
-		    if (uid == PRBADID)
-			continue;
-		    fprintf(rc, "au %d %d\n", uid, id);
-		    count++;
-		}
-		while (ng) {
-		    struct prentry c;
-		    code = pr_Read(ng, (char *)&c, sizeof(c));
-		    if (code)
-			return code;
-
-		    if ((id == ntohl(c.id)) && (c.flags & htonl(PRCONT))) {
-			for (i = 0; i < COSIZE; i++) {
-			    afs_int32 uid = ntohl(c.entries[i]);
-			    if (uid == 0)
-				break;
-			    if (uid == PRBADID)
-				continue;
-			    fprintf(rc, "au %d %d\n", uid, id);
-			    count++;
-			}
-		    } else {
-			fprintf(stderr, "Skipping continuation block at %d\n",
-				ng);
-			break;
-		    }
-		    ng = ntohl(c.next);
-		}
-#undef g
-#endif /* SUPERGROUPS */
 		na = ntohl(e.next);
 		while (na) {
 		    struct prentry c;
diff -Naur openafs_1.4.14.orig/src/rxdebug/rxdebug.c openafs_1.4.14/src/rxdebug/rxdebug.c
--- openafs_1.4.14.orig/src/rxdebug/rxdebug.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/rxdebug/rxdebug.c	2011-03-29 08:33:49.209181027 +0200
@@ -449,7 +449,7 @@
 			    printf("\n  Received %d bytes in %d packets\n",
 				   tconn.secStats.bytesReceived,
 				   tconn.secStats.packetsReceived);
-			    printf("  Sent %d bytes in %d packets\n",
+			    printf("  Sent %u bytes in %u packets\n",
 				   tconn.secStats.bytesSent,
 				   tconn.secStats.packetsSent);
 			} else
diff -Naur openafs_1.4.14.orig/src/tviced/Makefile.in openafs_1.4.14/src/tviced/Makefile.in
--- openafs_1.4.14.orig/src/tviced/Makefile.in	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/tviced/Makefile.in	2011-03-29 08:33:49.183182096 +0200
@@ -38,8 +38,7 @@
 DIROBJS=buffer.o dir.o salvage.o
 
 VOLOBJS= vnode.o volume.o vutil.o partition.o fssync.o purge.o \
-	 clone.o devname.o common.o ihandle.o listinodes.o namei_ops.o \
-	 fstab.o
+	 clone.o devname.o common.o ihandle.o listinodes.o namei_ops.o
 
 FSINTOBJS= afsaux.o afscbint.cs.o afsint.ss.o afsint.xdr.o
 
diff -Naur openafs_1.4.14.orig/src/ubik/recovery.c openafs_1.4.14/src/ubik/recovery.c
--- openafs_1.4.14.orig/src/ubik/recovery.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/ubik/recovery.c	2011-03-29 08:33:49.208181069 +0200
@@ -207,6 +207,7 @@
 			     sizeof(afs_int32));
 	if (code != sizeof(afs_int32))
 	    break;
+	opcode = ntohl(opcode);
 	if (opcode == LOGNEW) {
 	    /* handle begin trans */
 	    tpos += sizeof(afs_int32);
@@ -231,7 +232,7 @@
 	    if (code != 3 * sizeof(afs_int32))
 		break;
 	    /* otherwise, skip over the data bytes, too */
-	    tpos += buffer[2] + 3 * sizeof(afs_int32);
+	    tpos += ntohl(buffer[2]) + 3 * sizeof(afs_int32);
 	} else {
 	    ubik_dprint("corrupt log opcode (%d) at position %d\n", opcode,
 			tpos);
@@ -250,6 +251,7 @@
 				 sizeof(afs_int32));
 	    if (code != sizeof(afs_int32))
 		break;
+	    opcode = ntohl(opcode);
 	    if (opcode == LOGNEW) {
 		/* handle begin trans */
 		tpos += sizeof(afs_int32);
diff -Naur openafs_1.4.14.orig/src/util/Makefile.in openafs_1.4.14/src/util/Makefile.in
--- openafs_1.4.14.orig/src/util/Makefile.in	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/util/Makefile.in	2011-03-29 08:33:49.222180493 +0200
@@ -12,7 +12,7 @@
 
 objects = assert.o base64.o casestrcpy.o ktime.o volparse.o hostparse.o \
 	 hputil.o kreltime.o isathing.o get_krbrlm.o uuid.o serverLog.o \
-	 dirpath.o fileutil.o netutils.o flipbase64.o fstab.o \
+	 dirpath.o fileutil.o netutils.o flipbase64.o \
 	 afs_atomlist.o afs_lhash.o snprintf.o strlcat.o strlcpy.o \
 	 daemon.o rxkstats.o ${REGEX_OBJ}
 
@@ -392,4 +392,4 @@
 	    assert.c base64.c casestrcpy.c ktime.c volparse.c hostparse.c \
 	    hputil.c kreltime.c isathing.c get_krbrlm.c uuid.c serverLog.c \
 	    dirpath.c fileutil.c netutils.c flipbase64.c \
-	    afs_atomlist.c afs_lhash.c snprintf.c fstab.c
+	    afs_atomlist.c afs_lhash.c snprintf.c
diff -Naur openafs_1.4.14.orig/src/venus/fstrace.c openafs_1.4.14/src/venus/fstrace.c
--- openafs_1.4.14.orig/src/venus/fstrace.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/venus/fstrace.c	2011-03-29 08:33:49.228180245 +0200
@@ -1464,7 +1464,7 @@
  */
 
 #ifndef RPC_NLS_FORMAT
-#define RPC_NLS_FORMAT "%s.cat"
+#define RPC_NLS_FORMAT "/usr/share/openafs/%s.cat"
 #endif
 
 dce1_error_inq_text(status_to_convert, error_text, status)
@@ -1481,7 +1481,8 @@
     char component_name[4];
     char *facility_name;
     char filename_prefix[7];
-    char nls_filename[11];
+    /* strlen("/usr/share/openafs/") + 6 + strlen(".cat") + 1 */
+    char nls_filename[19 + 6 + 4 + 1];
     char alt_filename[80];
     char *message;
 #if defined(AFS_64BITPOINTER_ENV)
diff -Naur openafs_1.4.14.orig/src/viced/callback.c openafs_1.4.14/src/viced/callback.c
--- openafs_1.4.14.orig/src/viced/callback.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/viced/callback.c	2011-03-29 08:33:49.240179753 +0200
@@ -292,8 +292,6 @@
 				    struct VCBParams *parms);
 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
 					 struct VCBParams *parms);
-static int lih_r(register struct host *host, register int held,
-		 register struct host *hostp);
 static int GetSomeSpace_r(struct host *hostp, int locked);
 static int ClearHostCallbacks_r(struct host *hp, int locked);
 
@@ -1577,68 +1575,88 @@
     return (ntimedout > 0);
 }
 
-static struct host *lih_host;
-static int lih_host_held;
+/**
+ * parameters to pass to lih*_r from h_Enumerate_r when trying to find a host
+ * from which to clear callbacks.
+ */
+struct lih_params {
+    /**
+     * Points to the least interesting host found; try to clear callbacks on
+     * this host after h_Enumerate_r(lih*_r)'ing.
+     */
+    struct host *lih;
 
-static int
-lih_r(register struct host *host, register int held,
-      register struct host *hostp)
-{
-    if (host->cblist
-	&& ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
-	&& (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
-	if (lih_host != NULL && lih_host_held) {
-	    h_Release_r(lih_host);
-	}
-	lih_host = host;
-	lih_host_held = !held;
-	held = 1;
-    }
-    return held;
-}
+    /**
+     * The last host we got from lih*_r, but we couldn't clear its callbacks
+     * for some reason. Choose the next-best host after this one (with the
+     * current lih*_r, this means to only select hosts that have an ActiveCall
+     * newer than lastlih).
+     */
+    struct host *lastlih;
+
+    /**
+     * 1 if lih was held, 0 if it was not and should be released.
+     */
+    int lih_held;
+};
 
 /* This version does not allow 'host' to be selected unless its ActiveCall 
- * is newer than 'hostp' which is the host with the oldest ActiveCall from
- * the last pass (if it is provided).  We filter out any hosts that are
- * are held by other threads.
+ * is newer than 'params->lastlih' which is the host with the oldest
+ * ActiveCall from the last pass (if it is provided).  We filter out any hosts
+ * that are are held by other threads.
+ *
+ * There is a small problem here, but it may not be easily fixable. Say we
+ * select some host A, and give it back to GetSomeSpace_r. GSS_r for some
+ * reason cannot clear the callbacks on A, and so calls us again with
+ * lastlih = A. Suppose there is another host B that has the same ActiveCall
+ * time as A. We will now skip over host B, since
+ * 'hostB->ActiveCall > hostA->ActiveCall' is not true. This could result in
+ * us prematurely going to the GSS_r 2nd or 3rd pass, and making us a little
+ * inefficient. This should be pretty rare, though, except perhaps in cases
+ * with very small numbers of hosts.
+ *
+ * Also filter out any hosts with HOSTDELETED set. h_Enumerate_r should in
+ * theory not give these to us anyway, but be paranoid.
  */
 static int
-lih0_r(register struct host *host, register int held,
-      register struct host *hostp)
+lih0_r(struct host *host, int held, void *rock)
 {
+    struct lih_params *params = (struct lih_params *)rock;
+
     if (host->cblist
-	&& (hostp && host != hostp) 
+	&& (!(host->hostFlags & HOSTDELETED))
 	&& (!held && !h_OtherHolds_r(host))
-	&& (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
-	&& (!hostp || host->ActiveCall > hostp->ActiveCall)) {
-	if (lih_host != NULL && lih_host_held) {
-	    h_Release_r(lih_host);
+	&& (!params->lih || host->ActiveCall < params->lih->ActiveCall)
+	&& (!params->lastlih || host->ActiveCall > params->lastlih->ActiveCall)) {
+
+	if (params->lih && !params->lih_held) {
+	    h_Release_r(params->lih); /* release prev host */
 	}
-	lih_host = host;
-	lih_host_held = !held;
+
+	params->lih = host;
+	params->lih_held = held;
 	held = 1;
     }
     return held;
 }
 
-/* This version does not allow 'host' to be selected unless its ActiveCall 
- * is newer than 'hostp' which is the host with the oldest ActiveCall from
- * the last pass (if it is provided).  In this second varient, we do not 
- * prevent held hosts from being selected.
- */
+/* same as lih0_r, except we do not prevent held hosts from being selected. */
 static int
-lih1_r(register struct host *host, register int held,
-      register struct host *hostp)
+lih1_r(struct host *host, int held, void *rock)
 {
+    struct lih_params *params = (struct lih_params *)rock;
+
     if (host->cblist
-	&& (hostp && host != hostp) 
-	&& (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
-	&& (!hostp || host->ActiveCall > hostp->ActiveCall)) {
-	if (lih_host != NULL && lih_host_held) {
-	    h_Release_r(lih_host);
+	&& (!(host->hostFlags & HOSTDELETED))
+	&& (!params->lih || host->ActiveCall < params->lih->ActiveCall)
+	&& (!params->lastlih || host->ActiveCall > params->lastlih->ActiveCall)) {
+
+	if (params->lih && !params->lih_held) {
+	    h_Release_r(params->lih); /* release prev host */
 	}
-	lih_host = host;
-	lih_host_held = !held;
+
+	params->lih = host;
+	params->lih_held = held;
 	held = 1;
     }
     return held;
@@ -1659,8 +1677,10 @@
 static int
 GetSomeSpace_r(struct host *hostp, int locked)
 {
-    register struct host *hp, *hp1, *hp2;
+    struct host *hp;
+    struct lih_params params;
     int i = 0;
+    int lastlih_held = 1;
 
     cbstuff.GotSomeSpaces++;
     ViceLog(5,
@@ -1671,38 +1691,43 @@
     }
 
     i = 0;
-    hp1 = NULL;
-    hp2 = hostList;
+    params.lastlih = NULL;
+
     do {
-	lih_host = 0;
-	h_Enumerate_r(i == 0 ? lih0_r : lih1_r, hp2, (char *)hp1);
-	hp = lih_host;
+	params.lih = NULL;
+
+	h_Enumerate_r(i == 0 ? lih0_r : lih1_r, hostList, &params);
+
+	hp = params.lih;
+	if (params.lastlih && !lastlih_held) {
+	    h_Release_r(params.lastlih);
+	    lastlih_held = 1;
+	}
+	params.lastlih = NULL;
+
 	if (hp) {
-	    /* set in lih_r! private copy before giving up H_LOCK */
-	    int lih_host_held2=lih_host_held;   
+	    /* note that 'hp' was held by lih*_r; we will need to release it */
 	    cbstuff.GSS4++;
 	    if ((hp != hostp) && !ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
-		if (lih_host_held2)
+		if (!params.lih_held) {
 		    h_Release_r(hp);
+		}
 		return 0;
 	    }
-	    if (lih_host_held2) {
-		h_Release_r(hp);
-		hp = NULL;
-	    }
-	    hp1 = hp;
-	    hp2 = hostList;
+
+	    params.lastlih = hp;
+	    lastlih_held = params.lih_held;
+	    /* params.lastlih will be released on the next iteration, after
+	     * h_Enumerate_r */
+
 	} else {
 	    /*
 	     * Next time try getting callbacks from any host even if
-	     * it's deleted (that's actually great since we can freely
-	     * remove its callbacks) or it's held since the only other
-	     * option is starvation for the file server (i.e. until the
-	     * callback timeout arrives).
+	     * it's held, since the only other option is starvation for
+	     * the file server (i.e. until the callback timeout arrives).
 	     */
 	    i++;
-	    hp1 = NULL;
-	    hp2 = hostList;
+	    params.lastlih = NULL;
 	    cbstuff.GSS1++;
 	    ViceLog(5,
 		    ("GSS: Try harder for longest inactive host cnt= %d\n",
@@ -2159,10 +2184,10 @@
 	    if (host->callback_rxcon)
 		rx_DestroyConnection(host->callback_rxcon);
 	    host->callback_rxcon = conns[multi_i];
-            hashDelete_r(host->host, host->port, host);
+            h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
 	    host->host = interfaces[multi_i].addr;
 	    host->port = interfaces[multi_i].port;
-            hashInsert_r(host->host, host->port, host);
+            h_AddHostToAddrHashTable_r(host->host, host->port, host);
 	    connSuccess = conns[multi_i];
 	    rx_SetConnDeadTime(host->callback_rxcon, 50);
 	    rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
@@ -2252,11 +2277,11 @@
 	    H_LOCK;
 	    if (host->callback_rxcon)
 		rx_DestroyConnection(host->callback_rxcon);
-            hashDelete_r(host->host, host->port, host);
+            h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
 	    host->callback_rxcon = conns[multi_i];
 	    host->host = interfaces[multi_i].addr;
 	    host->port = interfaces[multi_i].port;
-            hashInsert_r(host->host, host->port, host);
+            h_AddHostToAddrHashTable_r(host->host, host->port, host);
 	    connSuccess = conns[multi_i];
 	    rx_SetConnDeadTime(host->callback_rxcon, 50);
 	    rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
diff -Naur openafs_1.4.14.orig/src/viced/host.c openafs_1.4.14/src/viced/host.c
--- openafs_1.4.14.orig/src/viced/host.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/viced/host.c	2011-03-29 08:33:49.239179794 +0200
@@ -10,7 +10,6 @@
 #include <afsconfig.h>
 #include <afs/param.h>
 
-
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
@@ -503,15 +502,17 @@
 	if (!h_OtherHolds_r(host)) {
 	    /* must avoid masking this until after h_OtherHolds_r runs
 	     * but it should be run before h_TossStuff_r */
-	    (host)->holds[h_holdSlot()] &= ~h_holdbit();
+	    h_Decrement_r(host);
 	    if ((host->hostFlags & HOSTDELETED)
 		|| (host->hostFlags & CLIENTDELETED)) {
 		h_TossStuff_r(host);
 	    }
-	} else
-	    (host)->holds[h_holdSlot()] &= ~h_holdbit();
-    } else
-	(host)->holds[h_holdSlot()] &= ~h_holdbit();
+	} else {
+	    h_Decrement_r(host);
+	}
+    } else {
+	h_Decrement_r(host);
+    }
 
     return 0;
 }
@@ -766,7 +767,7 @@
     host->host = rxr_HostOf(r_con);
     host->port = rxr_PortOf(r_con);
 
-    hashInsert_r(host->host, host->port, host);
+    h_AddHostToAddrHashTable_r(host->host, host->port, host);
 
     if (consolePort == 0) {	/* find the portal number for console */
 #if	defined(AFS_OSF_ENV)
@@ -887,12 +888,10 @@
 	assert(host);
 	if (!(host->hostFlags & HOSTDELETED) && host->interface
 	    && afs_uuid_equal(&host->interface->uuid, uuidp)) {
-	    break;
+	    return host;
 	}
-	host = NULL;
     }
-    return host;
-
+    return NULL;
 }				/*h_Lookup */
 
 
@@ -913,23 +912,39 @@
 {
     register struct client **cp, *client;
     int i;
+    int code;
 
-    /* if somebody still has this host held */
-    for (i = 0; (i < h_maxSlots) && (!(host)->holds[i]); i++);
-    if (i != h_maxSlots)
-	return;
+    /* make sure host doesn't go away over h_NBLock_r */
+    h_Hold_r(host);
+
+    code = h_NBLock_r(host);
+
+    /* don't use h_Release_r, since that may call h_TossStuff_r again */
+    h_Decrement_r(host);
 
     /* if somebody still has this host locked */
-    if (h_NBLock_r(host) != 0) {
+    if (code != 0) {
 	char hoststr[16];
 	ViceLog(0,
-		("Warning:  h_TossStuff_r failed; Host %s:%d was locked.\n",
-		 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+		("Warning:  h_TossStuff_r failed; Host 0x%lx (%s:%d) was locked.\n",
+		 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
 	return;
     } else {
 	h_Unlock_r(host);
     }
 
+    /* if somebody still has this host held */
+    /* we must check this _after_ h_NBLock_r, since h_NBLock_r can drop and
+     * reacquire H_LOCK */
+    for (i = 0; (i < h_maxSlots) && (!(host)->holds[i]); i++);
+    if (i != h_maxSlots) {
+	char hoststr[16];
+	ViceLog(0,
+		("Warning:  h_TossStuff_r failed; Host 0x%lx (%s:%d) was held.\n",
+		 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+	return;
+    }
+
     /* ASSUMPTION: rxi_FreeConnection() does not yield */
     for (cp = &host->FirstClient; (client = *cp);) {
 	if ((host->hostFlags & HOSTDELETED) || client->deleted) {
@@ -938,8 +953,8 @@
 	    if (code < 0) {
 		char hoststr[16];
 		ViceLog(0,
-			("Warning: h_TossStuff_r failed: Host %s:%d client %x was locked.\n",
-			 afs_inet_ntoa_r(host->host, hoststr),
+			("Warning: h_TossStuff_r failed: Host 0x%lx (%s:%d) client %x was locked.\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 			 ntohs(host->port), client));
 		return;
 	    }
@@ -947,8 +962,8 @@
 	    if (client->refCount) {
 		char hoststr[16];
 		ViceLog(0,
-			("Warning: h_TossStuff_r failed: Host %s:%d client %x refcount %d.\n",
-			 afs_inet_ntoa_r(host->host, hoststr),
+			("Warning: h_TossStuff_r failed: Host 0x%lx (%s:%d) client %x refcount %d.\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 			 ntohs(host->port), client, client->refCount));
 		/* This is the same thing we do if the host is locked */
 		ReleaseWriteLock(&client->lock);
@@ -970,9 +985,7 @@
     host->hostFlags &= ~CLIENTDELETED;
 
     if (host->hostFlags & HOSTDELETED) {
-        register struct h_AddrHashChain **ahp, *ath;
 	register struct rx_connection *rxconn;
-	afsUUID *uuidp;
 	struct AddrPort hostAddrPort;
 	int i;
 
@@ -991,44 +1004,22 @@
 
 	/* if alternate addresses do not exist */
 	if (!(host->interface)) {
-	    for (ahp = &hostAddrHashTable[h_HashIndex(host->host)]; (ath = *ahp);
-		 ahp = &ath->next) {
-		assert(ath->hostPtr);
-		if (ath->hostPtr == host) {
-		    *ahp = ath->next;
-		    free(ath);
-		    break;
-		}
-	    }
+	    h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
 	} else {
-            register struct h_UuidHashChain **uhp, *uth;
-	    /* delete the hash entry for the UUID */
-	    uuidp = &host->interface->uuid;
-	    for (uhp = &hostUuidHashTable[h_UuidHashIndex(uuidp)]; (uth = *uhp);
-		 uhp = &uth->next) {
-		assert(uth->hostPtr);
-		if (uth->hostPtr == host) {
-		    *uhp = uth->next;
-		    free(uth);
-		    break;
-		}
-	    }
-	    /* delete the hash entry for each alternate addresses */
+	    h_DeleteHostFromUuidHashTable_r(host);
+	    h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
+	    /* delete the hash entry for each valid alternate addresses */
 	    for (i = 0; i < host->interface->numberOfInterfaces; i++) {
 		hostAddrPort = host->interface->interface[i];
-
-                if (!hostAddrPort.valid)
-                    continue;
-
-		for (ahp = &hostAddrHashTable[h_HashIndex(hostAddrPort.addr)]; (ath = *ahp);
-		     ahp = &ath->next) {
-		    assert(ath->hostPtr);
-		    if (ath->hostPtr == host) {
-			*ahp = ath->next;
-			free(ath);
-			break;
-		    }
-		}
+		/*
+		 * if the interface addr/port is the primary, we already
+		 * removed it.  If the addr/port is not valid, its not
+		 * in the hash table.
+		 */
+		if (hostAddrPort.valid &&
+		    (host->host != hostAddrPort.addr ||
+		     host->port != hostAddrPort.port))
+		    h_DeleteHostFromAddrHashTable_r(hostAddrPort.addr, hostAddrPort.port, host);
 	    }
 	    free(host->interface);
 	    host->interface = NULL;
@@ -1184,65 +1175,124 @@
 
 /* inserts a new HashChain structure corresponding to this UUID */
 void
-hashInsertUuid_r(struct afsUUID *uuid, struct host *host)
+h_AddHostToUuidHashTable_r(struct afsUUID *uuid, struct host *host)
 {
     int index;
     struct h_UuidHashChain *chain;
+    char uuid1[128], uuid2[128];
+    char hoststr[16];
 
     /* hash into proper bucket */
     index = h_UuidHashIndex(uuid);
 
     /* don't add the same entry multiple times */
     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
+	if (!chain->hostPtr)
+	    continue;
+
 	if (chain->hostPtr->interface && 
-	    afs_uuid_equal(&chain->hostPtr->interface->uuid, uuid))
+	    afs_uuid_equal(&chain->hostPtr->interface->uuid, uuid)) {
+	    if (LogLevel >= 125) {
+		afsUUID_to_string(&chain->hostPtr->interface->uuid, uuid1, 127);
+		afsUUID_to_string(uuid, uuid2, 127);
+		ViceLog(125, ("h_AddHostToUuidHashTable_r: host 0x%lx (uuid %s) exists as %s:%d (uuid %s)\n",
+                             (unsigned long) host, uuid1,
+                             afs_inet_ntoa_r(chain->hostPtr->host, hoststr), 
+                             ntohs(chain->hostPtr->port), uuid2));
+	    }
 	    return;
+	}
     }
 
     /* insert into beginning of list for this bucket */
     chain = (struct h_UuidHashChain *)malloc(sizeof(struct h_UuidHashChain));
     if (!chain) {
-	ViceLog(0, ("Failed malloc in hashInsertUuid_r\n"));
+	ViceLog(0, ("Failed malloc in h_AddHostToUuidHashTable_r\n"));
 	assert(0);
     }
-    assert(chain);
     chain->hostPtr = host;
     chain->next = hostUuidHashTable[index];
     hostUuidHashTable[index] = chain;
+    if (LogLevel < 125)
+	return;
+    afsUUID_to_string(uuid, uuid2, 127);
+    ViceLog(125, 
+            ("h_AddHostToUuidHashTable_r: host 0x%lx (%s:%d) added as uuid %s\n",
+             (unsigned long) host, afs_inet_ntoa_r(chain->hostPtr->host, hoststr),
+             ntohs(chain->hostPtr->port), uuid));
 }
 
+/* deletes a HashChain structure corresponding to this host */
+int
+h_DeleteHostFromUuidHashTable_r(struct host *host)
+{
+    int index;
+    register struct h_UuidHashChain **uhp, *uth;
+    char uuid1[128];
+    char hoststr[16];
+ 
+    if (!host->interface)
+	return 0;
+ 
+    /* hash into proper bucket */
+    index = h_UuidHashIndex(&host->interface->uuid);
+     
+    if (LogLevel >= 125)
+	afsUUID_to_string(&host->interface->uuid, uuid1, 127);
+    for (uhp = &hostUuidHashTable[index]; (uth = *uhp); uhp = &uth->next) {
+	assert(uth->hostPtr);
+	if (uth->hostPtr == host) {
+	    ViceLog(125, 
+                    ("h_DeleteHostFromUuidHashTable_r: host 0x%lx (uuid %s %s:%d)\n",
+                     (unsigned long) host, uuid1, afs_inet_ntoa_r(host->host, hoststr),
+                     ntohs(host->port)));
+	    *uhp = uth->next;
+	    free(uth);
+	    return 1;
+	}
+    }
+    ViceLog(125, 
+            ("h_DeleteHostFromUuidHashTable_r: host 0x%lx (uuid %s %s:%d) not found\n",
+             (unsigned long) host, uuid1, afs_inet_ntoa_r(host->host, hoststr),
+             ntohs(host->port)));
+    return 0;
+}
 
 /* inserts a new HashChain structure corresponding to this address */
 void
-hashInsert_r(afs_uint32 addr, afs_uint16 port, struct host *host)
+h_AddHostToAddrHashTable_r(afs_uint32 addr, afs_uint16 port, struct host *host)
 {
     int index;
     struct h_AddrHashChain *chain;
     int found = 0;
-    char hoststr[16]; 
+    char hoststr[16], hoststr2[16]; 
   
     /* hash into proper bucket */
     index = h_HashIndex(addr);
 
     /* don't add the same entry multiple times */
     for (chain = hostAddrHashTable[index]; chain; chain = chain->next) {
-	if (chain->addr == addr && chain->port == port) {
-	    if (chain->hostPtr == host)
-		found = 1;
-	    else if (!(host->hostFlags & HOSTDELETED))
-		ViceLog(125, ("Addr %s:%d assigned to %x and %x.\n",
-			    afs_inet_ntoa_r(addr, hoststr), ntohs(port),
-			    host, chain));
+	if (chain->hostPtr == host) {
+	    if (chain->addr != addr || chain->port != port) {
+		ViceLog(0, 
+                       ("h_AddHostToAddrHashTable_r: host 0x%lx exists as %s:%d when adding %s:%d\n",
+                        (unsigned long) host, afs_inet_ntoa_r(chain->addr, hoststr),
+                        ntohs(chain->port), afs_inet_ntoa_r(addr, hoststr2), 
+                        ntohs(port)));
+	    } else
+		ViceLog(125, 
+                       ("h_AddHostToAddrHashTable_r: host 0x%lx (%s:%d) already hashed\n",
+                        (unsigned long) host, afs_inet_ntoa_r(chain->addr, hoststr),
+                        ntohs(chain->port)));
+           
+	    return;
 	}
     }
 
-    if (found)
-	return;
-
     /* insert into beginning of list for this bucket */
     chain = (struct h_AddrHashChain *)malloc(sizeof(struct h_AddrHashChain));
     if (!chain) {
-	ViceLog(0, ("Failed malloc in hashInsert_r\n"));
+	ViceLog(0, ("Failed malloc in h_AddHostToAddrHashTable_r\n"));
 	assert(0);
     }
     chain->hostPtr = host;
@@ -1250,13 +1300,14 @@
     chain->addr = addr;
     chain->port = port;
     hostAddrHashTable[index] = chain;
+    ViceLog(125, ("h_AddHostToAddrHashTable_r: host 0x%lx added as %s:%d\n",
+                  (unsigned long) host, afs_inet_ntoa_r(addr, hoststr), ntohs(port)));
 }
 
 /*
- * This is called with host locked and held. At this point, the
- * hostAddrHashTable should not have entries for the alternate
- * interfaces. This function has to insert these entries in the
- * hostAddrHashTable.
+ * This is called with host locked and held. 
+ * It is called to either validate or add an additional interface
+ * address/port on the specified host.  
  *
  * All addresses are in network byte order.
  */
@@ -1279,22 +1330,25 @@
     for (i = 0; i < number; i++) {
 	if (host->interface->interface[i].addr == addr &&
             host->interface->interface[i].port == port) {
-	    ViceLog(125, ("addInterfaceAddr : host %x (%s:%d) addr %s:%d : found, valid: %d\n",
-			  host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
-			  afs_inet_ntoa_r(addr, hoststr2), ntohs(port),
-			  host->interface->interface[i].valid));
+	    ViceLog(125, 
+                   ("addInterfaceAddr : found host 0x%lx (%s:%d) adding %s:%d%s\n",
+                    (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
+                    ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
+                    ntohs(port), host->interface->interface[i].valid ? "" : 
+                    ", validating"));
 
 	    if (host->interface->interface[i].valid == 0) {
-		hashInsert_r(addr, port, host);
 		host->interface->interface[i].valid = 1;
+		h_AddHostToAddrHashTable_r(addr, port, host);
 	    }
 	    return 0;
         }
     }
 
-    ViceLog(125, ("addInterfaceAddr : host %x (%s:%d) addr %s:%d : not found, adding\n",
-		  host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
-		  afs_inet_ntoa_r(addr, hoststr2), ntohs(port)));
+    ViceLog(125, ("addInterfaceAddr : host 0x%lx (%s:%d) adding %s:%d\n",
+                 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
+                 ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
+                 ntohs(port)));
     
     interface = (struct Interface *)
 	malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * number));
@@ -1306,9 +1360,12 @@
     interface->uuid = host->interface->uuid;
     for (i = 0; i < number; i++)
 	interface->interface[i] = host->interface->interface[i];
+
+    /* Add the new valid interface */
     interface->interface[number].addr = addr;
     interface->interface[number].port = port;
     interface->interface[number].valid = 1;
+    h_AddHostToAddrHashTable_r(addr, port, host);
     free(host->interface);
     host->interface = interface;
 
@@ -1317,10 +1374,7 @@
 
 
 /*
- * This is called with host locked and held. At this point, the
- * hostAddrHashTable should not be having entries for the alternate
- * interfaces. This function has to insert these entries in the
- * hostAddrHashTable.
+ * This is called with host locked and held.
  *
  * All addresses are in network byte order.
  */
@@ -1329,16 +1383,16 @@
 {
     int i;
     int number;
-    int found;
     struct Interface *interface;
     char hoststr[16], hoststr2[16];
 
     assert(host);
     assert(host->interface);
 
-    ViceLog(125, ("removeInterfaceAddr : host %x (%s:%d) addr %s:%d\n", 
-		   host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), 
-		   afs_inet_ntoa_r(addr, hoststr2), ntohs(port)));
+    ViceLog(125, ("removeInterfaceAddr : host 0x%lx (%s:%d) addr %s:%d\n",
+                 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
+                 ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
+                 ntohs(port)));
 
     /*
      * Make sure this address is on the list of known addresses
@@ -1346,26 +1400,62 @@
      */
     interface = host->interface;
     number = host->interface->numberOfInterfaces;
-    for (i = 0, found = 0; i < number && !found; i++) {
-	if (interface->interface[i].addr == addr &&
-	    interface->interface[i].port == port) {
-	    found = 1;
-            interface->interface[i].valid = 0;
-	}
-    }
-    if (found) {
-	number--;
-	for (; i < number; i++) {
-	    interface->interface[i] = interface->interface[i+1];
+    for (i = 0; i < number; i++) {
+        if (interface->interface[i].addr == addr &&
+            interface->interface[i].port == port) {
+	    if (interface->interface[i].valid)
+		h_DeleteHostFromAddrHashTable_r(addr, port, host);
+	    number--;
+	    for (; i < number; i++) {
+		interface->interface[i] = interface->interface[i+1];
+	    }
+	    interface->numberOfInterfaces = number;
+	    return 0;
 	}
-	interface->numberOfInterfaces = number;
-    }
+    }  
+    /* not found */
+    return 0;
+}
+
+/*
+ * This is called with host locked and held.
+ *
+ * All addresses are in network byte order.
+ */
+int
+invalidateInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
+{
+    int i;
+    int number;
+    struct Interface *interface;
+    char hoststr[16], hoststr2[16];
+
+    assert(host);
+    assert(host->interface);
+    
+    ViceLog(125, ("invalidateInterfaceAddr : host 0x%lx (%s:%d) addr %s:%d\n",
+                 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
+                 ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
+                 ntohs(port)));
 
     /*
-     * Remove the hash table entry for this address
+     * Make sure this address is on the list of known addresses
+     * for this host.
      */
-    hashDelete_r(addr, port, host);
-
+    interface = host->interface;
+    number = host->interface->numberOfInterfaces;
+    for (i = 0; i < number; i++) {
+	if (interface->interface[i].addr == addr &&
+            interface->interface[i].port == port) {
+	    if (interface->interface[i].valid) {
+		h_DeleteHostFromAddrHashTable_r(addr, port, host);
+		interface->interface[i].valid = 0;
+	    }
+	    return 0;
+	}
+    }
+    
+    /* not found */
     return 0;
 }
 
@@ -1383,62 +1473,53 @@
 {
     int i;
     char hoststr[16], hoststr2[16];
+    struct rx_connection *rxconn;
 
-    if (!host->interface) {
+    if (!host->interface || host->interface->numberOfInterfaces == 1) {
         if (host->host == addr && host->port == port) {
             ViceLog(25,
-                    ("Removing only address for host %x (%s:%d), deleting host.\n",
-                     host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+                    ("Removing only address for host 0x%lx (%s:%d), deleting host.\n",
+                     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
             host->hostFlags |= HOSTDELETED;
+            /* 
+             * Do not remove the primary addr/port from the hash table.
+             * It will be ignored due to the HOSTDELETED flag and will
+             * be removed when h_TossStuff_r() cleans up the HOSTDELETED
+             * host.  Removing it here will only result in a search for 
+             * the host/addr/port in the hash chain which will fail.
+             */
+	} else {
+            ViceLog(0,
+                    ("Removing address that does not belong to host 0x%lx (%s:%d).\n",
+                     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
         }
     } else {
-        removeInterfaceAddr_r(host, host->host, host->port);
-        if (host->interface->numberOfInterfaces == 0) {
-            ViceLog(25,
-                     ("Removed only address for host %x (%s:%d), no alternate interfaces, deleting host.\n",
-                       host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
-            host->hostFlags |= HOSTDELETED;
-        } else {
+	if (host->host == addr && host->port == port)  {
+	    removeInterfaceAddr_r(host, addr, port);
 
             for (i=0; i < host->interface->numberOfInterfaces; i++) {
                 if (host->interface->interface[i].valid) {
                     ViceLog(25,
-                             ("Removed address for host %x (%s:%d), new primary interface %s:%d.\n",
-                               host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
+                             ("Removed address for host 0x%lx (%s:%d), new primary interface %s:%d.\n",
+                               (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
                                afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr2), 
                                ntohs(host->interface->interface[i].port)));
                     host->host = host->interface->interface[i].addr;
                     host->port = host->interface->interface[i].port;
-                    hashInsert_r(host->host, host->port, host);
+                    h_AddHostToAddrHashTable_r(host->host, host->port, host);
                     break;
                 }
             }
 
             if (i == host->interface->numberOfInterfaces) {
                 ViceLog(25,
-                         ("Removed only address for host %x (%s:%d), no valid alternate interfaces, deleting host.\n",
-                           host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+                         ("Removed only address for host 0x%lx (%s:%d), no valid alternate interfaces, deleting host.\n",
+                          (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
                 host->hostFlags |= HOSTDELETED;
+		/* addr/port was removed from the hash table */
+		host->host = 0;
+		host->port = 0;
             } else {
-                struct rx_connection *rxconn;
-
-                rxconn = host->callback_rxcon;
-                host->callback_rxcon = NULL;
-
-                if (rxconn) {
-                    struct client *client;
-                    /*
-                    * If rx_DestroyConnection calls h_FreeConnection we will
-                    * deadlock on the host_glock_mutex. Work around the problem
-                    * by unhooking the client from the connection before
-                    * destroying the connection.
-                    */
-                    client = rx_GetSpecific(rxconn, rxcon_client_key);
-                    rx_SetSpecific(rxconn, rxcon_client_key, (void *)0);
-                    rx_DestroyConnection(rxconn);
-		    rxconn = NULL;
-                }
-
                 if (!sc)
                     sc = rxnull_NewClientSecurityObject();
                 host->callback_rxcon =
@@ -1446,6 +1527,9 @@
                 rx_SetConnDeadTime(host->callback_rxcon, 50);
                 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
             }
+	} else {
+	    /* not the primary addr/port, just invalidate it */
+	    invalidateInterfaceAddr_r(host, addr, port);
         }
     }
 
@@ -1527,8 +1611,8 @@
              * waited for the lock. */
 	    h_Unlock_r(host);
 	    ViceLog(125,
-		    ("Host %s:%d starting h_Lookup again\n",
-		     afs_inet_ntoa_r(host->host, hoststr),
+		    ("Host 0x%lx (%s:%d) starting h_Lookup again\n",
+		     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 		     ntohs(host->port)));
 	    if (!*heldp)
 		h_Release_r(host);
@@ -1594,8 +1678,8 @@
 		 * that we maintain some extra callback state information */
 		if (host->interface) {
 		    ViceLog(0,
-			    ("Host %x (%s:%d) used to support WhoAreYou, deleting.\n",
-			     host, 
+			    ("Host 0x%lx (%s:%d) used to support WhoAreYou, deleting.\n",
+			     (unsigned long) host,
 			     afs_inet_ntoa_r(host->host, hoststr),
 			     ntohs(host->port)));
 		    host->hostFlags |= HOSTDELETED;
@@ -1646,8 +1730,8 @@
                     removeAddress_r(host, haddr, hport);
 		} else {
 		    ViceLog(25,
-			    ("Uuid doesn't match host %x (%s:%d).\n",
-			     host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+			    ("Uuid doesn't match host 0x%lx (%s:%d).\n",
+			     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
 		    
 		    removeAddress_r(host, host->host, host->port);
 		}
@@ -1684,8 +1768,8 @@
                      * callback connection, and destroy the old one.
                      */
                     struct rx_connection *rxconn;
-                    ViceLog(0,("CB: ProbeUuid for host %x (%s:%d) failed %d\n",
-			       host, 
+                    ViceLog(0,("CB: ProbeUuid for host 0x%lx (%s:%d) failed %d\n",
+			       (unsigned long) host,
 			       afs_inet_ntoa_r(host->host, hoststr),
 			       ntohs(host->port),code2));
 		    /*
@@ -1736,8 +1820,8 @@
 		goto gethost_out;
 	    } else {
 		ViceLog(0,
-			("CB: WhoAreYou failed for host %x (%s:%d), error %d\n",
-			 host, afs_inet_ntoa_r(host->host, hoststr),
+			("CB: WhoAreYou failed for host 0x%lx (%s:%d), error %d\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 			 ntohs(host->port), code));
 		host->hostFlags |= VENUSDOWN;
 	    }
@@ -1754,14 +1838,14 @@
 	if (!(host->hostFlags & ALTADDR)) {
 	    /* another thread is doing the initialisation */
 	    ViceLog(125,
-		    ("Host %s:%d waiting for host-init to complete\n",
-		     afs_inet_ntoa_r(host->host, hoststr),
+		    ("Host 0x%lx (%s:%d) waiting for host-init to complete\n",
+		     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 		     ntohs(host->port)));
 	    h_Lock_r(host);
 	    h_Unlock_r(host);
 	    ViceLog(125,
-		    ("Host %s:%d starting h_Lookup again\n",
-		     afs_inet_ntoa_r(host->host, hoststr),
+		    ("Host 0x%lx (%s:%d) starting h_Lookup again\n",
+		     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 		     ntohs(host->port)));
 	    if (!*heldp)
 		h_Release_r(host);
@@ -1782,8 +1866,8 @@
 	    if (host->interface)
 		afsUUID_to_string(&host->interface->uuid, uuid2, 127);
 	    ViceLog(0,
-		    ("CB: new identity for host %s:%d, deleting(%x %x %s %s)\n",
-		     afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
+		    ("CB: new identity for host 0x%lx (%s:%d), deleting(%x %x %s %s)\n",
+		     (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
 		     identP->valid, host->interface,
 		     identP->valid ? uuid1 : "",
 		     host->interface ? uuid2 : ""));
@@ -1829,8 +1913,8 @@
 		if (!pident)
 		    rx_SetSpecific(tcon, rxcon_ident_key, identP);
 		ViceLog(25,
-			("Host %s:%d does not support WhoAreYou.\n",
-			 afs_inet_ntoa_r(host->host, hoststr),
+			("Host 0x%lx (%s:%d) does not support WhoAreYou.\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 			 ntohs(host->port)));
 		code = 0;
 	    } else if (code == 0) {
@@ -1850,8 +1934,8 @@
 		if (!pident)
 		    rx_SetSpecific(tcon, rxcon_ident_key, identP);
 		ViceLog(25,
-			("WhoAreYou success on %s:%d\n",
-			 afs_inet_ntoa_r(host->host, hoststr),
+			("WhoAreYou success on 0x%lx (%s:%d)\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 			 ntohs(host->port)));
 	    }
 	    if (code == 0 && !identP->valid) {
@@ -1906,8 +1990,8 @@
 			     * MultiProbeAlternateAddress_r() will remove the
 			     * alternate interfaces that do not have the same
 			     * Uuid. */
-			    ViceLog(0,("CB: ProbeUuid for %s:%d failed %d\n",
-					 afs_inet_ntoa_r(oldHost->host, hoststr),
+			    ViceLog(0,("CB: ProbeUuid for 0x%lx (%s:%d) failed %d\n",
+                                        (unsigned long) oldHost, afs_inet_ntoa_r(oldHost->host, hoststr),
 					 ntohs(oldHost->port),code2));
 			    MultiProbeAlternateAddress_r(oldHost);
                             probefail = 1;
@@ -1927,8 +2011,8 @@
 			struct rx_connection *rxconn;
 
 			ViceLog(25,
-				("CB: Host %x (%s:%d) has new addr %s:%d\n",
-				  oldHost, 
+				("CB: Host 0x%lx (%s:%d) has new addr %s:%d\n",
+                                  (unsigned long) oldHost,
                                   afs_inet_ntoa_r(oldHost->host, hoststr2),
 				  ntohs(oldHost->port),
                                   afs_inet_ntoa_r(haddr, hoststr),
@@ -1947,23 +2031,24 @@
 			     */
 			    removeInterfaceAddr_r(oldHost, oldHost->host, oldHost->port);
 			} else {
-			    int i, found;
+			    int i;
 			    struct Interface *interface = oldHost->interface;
 			    int number = oldHost->interface->numberOfInterfaces;
-			    for (i = 0, found = 0; i < number; i++) {
+			    for (i = 0; i < number; i++) {
 				if (interface->interface[i].addr == haddr &&
 				    interface->interface[i].port != hport) {
-				    found = 1;
+				    /* 
+				     * We have just been contacted by a client
+				     * that has been seen from behind a NAT 
+				     * and at least one other address.
+				     */
+				    removeInterfaceAddr_r(oldHost, haddr, 
+					interface->interface[i].port);
 				    break;
 				}
 			    }
-			    if (found) {
-				/* We have just been contacted by a client that has been
-				 * seen from behind a NAT and at least one other address.
-				 */
-				removeInterfaceAddr_r(oldHost, haddr, interface->interface[i].port);
-			    }
 			}
+			h_AddHostToAddrHashTable_r(haddr, hport, oldHost);
 			oldHost->host = haddr;
 			oldHost->port = hport;
 			rxconn = oldHost->callback_rxcon;
@@ -1982,7 +2067,7 @@
 		    /* the new host is held and locked */
 		} else {
 		    /* This really is a new host */
-		    hashInsertUuid_r(&identP->uuid, host);
+		    h_AddHostToUuidHashTable_r(&identP->uuid, host);
 		    cb_conn = host->callback_rxcon;
 		    rx_GetConnection(cb_conn);		
 		    H_UNLOCK;
@@ -1994,8 +2079,8 @@
 		    H_LOCK;
 		    if (code == 0) {
 			ViceLog(25,
-				("InitCallBackState3 success on %s:%d\n",
-				 afs_inet_ntoa_r(host->host, hoststr),
+				("InitCallBackState3 success on 0x%lx (%s:%d)\n",
+				 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
 				 ntohs(host->port)));
 			assert(interfValid == 1);
 			initInterfaceAddr_r(host, &interf);
@@ -2004,13 +2089,13 @@
 	    }
 	    if (code) {
 		ViceLog(0,
-			("CB: RCallBackConnectBack failed for host %x (%s:%d)\n",
-			 host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+			("CB: RCallBackConnectBack failed for host 0x%lx (%s:%d)\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
 		host->hostFlags |= VENUSDOWN;
 	    } else {
 		ViceLog(125,
-			("CB: RCallBackConnectBack succeeded for host %x (%s:%d)\n",
-			 host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+			("CB: RCallBackConnectBack succeeded for host 0x%lx (%s:%d)\n",
+			 (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
 		host->hostFlags |= RESETDONE;
 	    }
 	}
@@ -2358,8 +2443,8 @@
 	    if (code) {
 		char hoststr[16];
 		ViceLog(0,
-			("pr_GetCPS failed(%d) for user %d, host %s:%d\n",
-			 code, viceid, afs_inet_ntoa_r(client->host->host,
+			("pr_GetCPS failed(%d) for user %d, host 0x%lx (%s:%d)\n",
+			 code, viceid, (unsigned long) client->host, afs_inet_ntoa_r(client->host->host,
 						       hoststr),
 			 ntohs(client->host->port)));
 
@@ -3012,7 +3097,7 @@
 		     * back state, because break delayed callbacks (called when a
 		     * message is received from the workstation) will always send a 
 		     * break all call backs to the workstation if there is no
-		     *callback.
+		     * callback.
 		     */
 		}
 	    } else {
@@ -3105,7 +3190,7 @@
 		     * back state, because break delayed callbacks (called when a
 		     * message is received from the workstation) will always send a 
 		     * break all call backs to the workstation if there is no
-		     *callback.
+		     * callback.
 		     */
 		}
 	    } else {
@@ -3178,9 +3263,8 @@
 
 /*
  * This is called with host locked and held. At this point, the
- * hostAddrHashTable should not have any entries for the alternate
- * interfaces. This function has to insert these entries in the
- * hostAddrHashTable.
+ * hostAddrHashTable has an entry for the primary addr/port inserted
+ * by h_Alloc_r().  No other interfaces should be considered valid.
  *
  * The addresses in the interfaceAddr list are in host byte order.
  */
@@ -3298,7 +3382,8 @@
 	 * are coming from fully connected hosts (no NAT/PATs)
 	 */
 	interface->interface[i].port = port7001;
-        interface->interface[i].valid = 1;      /* valid until a conflict is found */
+	interface->interface[i].valid = 
+	    (interf->addr_in[i] == myAddr && port7001 == myPort) ? 1 : 0;
     }
 
     interface->uuid = interf->uuid;
@@ -3306,13 +3391,15 @@
     assert(!host->interface);
     host->interface = interface;
 
-    afsUUID_to_string(&interface->uuid, uuidstr, 127);
-
-    ViceLog(125, ("--- uuid %s\n", uuidstr));
-    for (i = 0; i < host->interface->numberOfInterfaces; i++) {
-	ViceLog(125, ("--- alt address %s:%d\n", 
-		       afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
-		       ntohs(host->interface->interface[i].port)));
+    if (LogLevel >= 125) {
+	afsUUID_to_string(&interface->uuid, uuidstr, 127);
+       
+	ViceLog(125, ("--- uuid %s\n", uuidstr));
+	for (i = 0; i < host->interface->numberOfInterfaces; i++) {
+	    ViceLog(125, ("--- alt address %s:%d\n", 
+		afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
+		ntohs(host->interface->interface[i].port)));
+	}
     }
 
     return 0;
@@ -3321,24 +3408,32 @@
 /* deleted a HashChain structure for this address and host */
 /* returns 1 on success */
 int
-hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *
-				host)
+h_DeleteHostFromAddrHashTable_r(afs_uint32 addr, afs_uint16 port, 
+                               struct host *host)
 {
-    int flag = 0;
+    char hoststr[16];
     register struct h_AddrHashChain **hp, *th;
 
-    for (hp = &hostAddrHashTable[h_HashIndex(addr)]; (th = *hp);) {
+    if (addr == 0 && port == 0)
+	return 1;
+
+    for (hp = &hostAddrHashTable[h_HashIndex(addr)]; (th = *hp); 
+	hp = &th->next) {
 	assert(th->hostPtr);
 	if (th->hostPtr == host && th->addr == addr && th->port == port) {
+	    ViceLog(125, ("h_DeleteHostFromAddrHashTable_r: host 0x%lx (%s:%d)\n",
+                         (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
+                         ntohs(host->port)));
 	    *hp = th->next;
 	    free(th);
-	    flag = 1;
-	    break;
-	} else {
-	    hp = &th->next;
-	}
+	    return 1;
+        }
     }
-    return flag;
+    ViceLog(125, 
+           ("h_DeleteHostFromAddrHashTable_r: host 0x%lx (%s:%d) not found\n",
+            (unsigned long) host, afs_inet_ntoa_r(host->host, hoststr),
+            ntohs(host->port)));
+    return 0;
 }
 
 
@@ -3355,9 +3450,9 @@
     if (host->interface) {
 	/* check alternate addresses */
 	number = host->interface->numberOfInterfaces;
-        if (number == 0)
+        if (number == 0) {
             ViceLog(level, ("no-addresses "));
-        else {
+        } else {
             for (i = 0; i < number; i++)
                 ViceLog(level, ("%s:%d ", afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
                                 ntohs(host->interface->interface[i].port)));
diff -Naur openafs_1.4.14.orig/src/viced/host.h openafs_1.4.14/src/viced/host.h
--- openafs_1.4.14.orig/src/viced/host.h	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/viced/host.h	2011-03-29 08:33:49.239179794 +0200
@@ -176,6 +176,7 @@
 #define h_holdbit()  ( 1<<h_holdIndex() )
 
 #define h_Hold_r(host)   ((host)->holds[h_holdSlot()] |= h_holdbit())
+#define h_Decrement_r(host) ((host)->holds[h_holdSlot()] &= ~h_holdbit())
 extern int h_Release(register struct host *host);
 extern int h_Release_r(register struct host *host);
 
@@ -207,8 +208,6 @@
 extern struct host *h_Alloc_r(register struct rx_connection *r_con);
 extern int h_Lookup_r(afs_uint32 hostaddr, afs_uint16 hport,
 			       int *heldp, struct host **hostp);
-extern void   hashInsert_r(afs_uint32 addr, afs_uint16 port, 
-			   struct host* host);
 extern struct host *h_LookupUuid_r(afsUUID * uuidp);
 extern void h_Enumerate(int (*proc) (), char *param);
 extern struct host *h_GetHost_r(struct rx_connection *tcon, int *heldp);
@@ -222,9 +221,9 @@
 extern void h_GetWorkStats();
 extern void h_flushhostcps(register afs_uint32 hostaddr,
 			   register afs_uint16 hport);
-extern void hashInsertUuid_r(struct afsUUID *uuid, struct host *host);
-extern void hashInsert_r(afs_uint32 addr, afs_uint16 port, struct host *host);
-extern int hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *host);
+extern void h_AddHostToUuidHashTable_r(struct afsUUID *uuid, struct host *host);
+extern void h_AddHostToAddrHashTable_r(afs_uint32 addr, afs_uint16 port, struct host *host);
+extern int h_DeleteHostFromAddrHashTable_r(afs_uint32 addr, afs_uint16 port, struct host *host);
 extern int initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf);
 extern int addInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port);
 extern int removeInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port);
diff -Naur openafs_1.4.14.orig/src/vol/vol-salvage.c openafs_1.4.14/src/vol/vol-salvage.c
--- openafs_1.4.14.orig/src/vol/vol-salvage.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/vol/vol-salvage.c	2011-03-29 08:33:49.104185344 +0200
@@ -188,6 +188,9 @@
 #include "viceinode.h"
 #include "salvage.h"
 #include "volinodes.h"		/* header magic number, etc. stuff */
+#include <afs/acl.h>
+#include <afs/prs_fs.h>
+
 #ifdef AFS_NT40_ENV
 #include <pthread.h>
 #endif
@@ -3459,6 +3462,372 @@
     return;
 }
 
+/**
+ * Get a new FID that can be used to create a new file.
+ *
+ * @param[in] volHeader vol header for the volume
+ * @param[in] class     what type of vnode we'll be creating (vLarge or vSmall)
+ * @param[out] afid     the FID that we can use (only Vnode and Unique are set)
+ * @param[inout] maxunique  max uniquifier for all vnodes in the volume;
+ *                          updated to the new max unique if we create a new
+ *                          vnode
+ */
+static void
+GetNewFID(VolumeDiskData *volHeader, VnodeClass class, AFSFid *afid,
+          Unique *maxunique)
+{
+    int i;
+    for (i = 0; i < vnodeInfo[class].nVnodes; i++) {
+	if (vnodeInfo[class].vnodes[i].type == vNull) {
+	    break;
+	}
+    }
+    if (i == vnodeInfo[class].nVnodes) {
+	/* no free vnodes; make a new one */
+	vnodeInfo[class].nVnodes++;
+	vnodeInfo[class].vnodes = realloc(vnodeInfo[class].vnodes,
+	                                  sizeof(struct VnodeEssence) * (i+1));
+	vnodeInfo[class].vnodes[i].type = vNull;
+    }
+
+    afid->Vnode = bitNumberToVnodeNumber(i, class);
+
+    if (volHeader->uniquifier < (*maxunique + 1)) {
+	/* header uniq is bad; it will get bumped by 2000 later */
+	afid->Unique = *maxunique + 1 + 2000;
+	(*maxunique)++;
+    } else {
+	/* header uniq seems okay; just use that */
+	afid->Unique = *maxunique = volHeader->uniquifier++;
+    }
+}
+
+/**
+ * Create a vnode for a README file explaining not to use a recreated-root vol.
+ *
+ * @param[in] volHeader vol header for the volume
+ * @param[in] alinkH    ihandle for i/o for the volume
+ * @param[in] vid       volume id
+ * @param[inout] maxunique  max uniquifier for all vnodes in the volume;
+ *                          updated to the new max unique if we create a new
+ *                          vnode
+ * @param[out] afid     FID for the new readme vnode
+ * @param[out] ainode   the inode for the new readme file
+ *
+ * @return operation status
+ *  @retval 0 success
+ *  @retval -1 error
+ */
+static int
+CreateReadme(VolumeDiskData *volHeader, IHandle_t *alinkH,
+             VolumeId vid, Unique *maxunique, AFSFid *afid, Inode *ainode)
+{
+    Inode readmeinode;
+    struct VnodeDiskObject *rvnode = NULL;
+    afs_sfsize_t bytes;
+    IHandle_t *readmeH = NULL;
+    struct VnodeEssence *vep;
+    afs_fsize_t length;
+    time_t now = time(NULL);
+
+    /* Try to make the note brief, but informative. Only administrators should
+     * be able to read this file at first, so we can hopefully assume they
+     * know what AFS is, what a volume is, etc. */
+    char readme[] =
+"This volume has been salvaged, but has lost its original root directory.\n"
+"The root directory that exists now has been recreated from orphan files\n"
+"from the rest of the volume. This recreated root directory may interfere\n"
+"with old cached data on clients, and there is no way the salvager can\n"
+"reasonably prevent that. So, it is recommended that you do not continue to\n"
+"use this volume, but only copy the salvaged data to a new volume.\n"
+"Continuing to use this volume as it exists now may cause some clients to\n"
+"behave oddly when accessing this volume.\n"
+"\n\t -- Your friendly neighborhood OpenAFS salvager\n";
+    /* ^ the person reading this probably just lost some data, so they could
+     * use some cheering up. */
+
+    /* -1 for the trailing NUL */
+    length = sizeof(readme) - 1;
+
+    GetNewFID(volHeader, vSmall, afid, maxunique);
+
+    vep = &vnodeInfo[vSmall].vnodes[vnodeIdToBitNumber(afid->Vnode)];
+
+    /* create the inode and write the contents */
+    readmeinode = IH_CREATE(alinkH, fileSysDevice, fileSysPath, 0, vid,
+                            afid->Vnode, afid->Unique, 1);
+    if (!VALID_INO(readmeinode)) {
+	Log("CreateReadme: readme IH_CREATE failed\n");
+	goto error;
+    }
+
+    IH_INIT(readmeH, fileSysDevice, vid, readmeinode);
+    bytes = IH_IWRITE(readmeH, 0, readme, length);
+    IH_RELEASE(readmeH);
+
+    if (bytes != length) {
+	Log("CreateReadme: IWRITE failed (%d/%d)\n", (int)bytes,
+	    (int)sizeof(readme));
+	goto error;
+    }
+
+    /* create the vnode and write it out */
+    rvnode = malloc(SIZEOF_SMALLDISKVNODE);
+    if (!rvnode) {
+	Log("CreateRootDir: error alloc'ing memory\n");
+	goto error;
+    }
+
+    rvnode->type = vFile;
+    rvnode->cloned = 0;
+    rvnode->modeBits = 0777;
+    rvnode->linkCount = 1;
+    VNDISK_SET_LEN(rvnode, length);
+    rvnode->uniquifier = afid->Unique;
+    rvnode->dataVersion = 1;
+    VNDISK_SET_INO(rvnode, readmeinode);
+    rvnode->unixModifyTime = rvnode->serverModifyTime = now;
+    rvnode->author = 0;
+    rvnode->owner = 0;
+    rvnode->parent = 1;
+    rvnode->group = 0;
+    rvnode->vnodeMagic = VnodeClassInfo[vSmall].magic;
+
+    bytes = IH_IWRITE(vnodeInfo[vSmall].handle,
+                      vnodeIndexOffset(&VnodeClassInfo[vSmall], afid->Vnode),
+                      (char*)rvnode, SIZEOF_SMALLDISKVNODE);
+
+    if (bytes != SIZEOF_SMALLDISKVNODE) {
+	Log("CreateReadme: IH_IWRITE failed (%d/%d)\n", (int)bytes,
+	    (int)SIZEOF_SMALLDISKVNODE);
+	goto error;
+    }
+
+    /* update VnodeEssence for new readme vnode */
+    vnodeInfo[vSmall].nAllocatedVnodes++;
+    vep->count = 0;
+    vep->blockCount = nBlocks(length);
+    vnodeInfo[vSmall].volumeBlockCount += vep->blockCount;
+    vep->parent = rvnode->parent;
+    vep->unique = rvnode->uniquifier;
+    vep->modeBits = rvnode->modeBits;
+    vep->InodeNumber = VNDISK_GET_INO(rvnode);
+    vep->type = rvnode->type;
+    vep->author = rvnode->author;
+    vep->owner = rvnode->owner;
+    vep->group = rvnode->group;
+
+    free(rvnode);
+    rvnode = NULL;
+
+    vep->claimed = 1;
+    vep->changed = 0;
+    vep->salvaged = 1;
+    vep->todelete = 0;
+
+    *ainode = readmeinode;
+
+    return 0;
+
+ error:
+    if (IH_DEC(alinkH, readmeinode, vid)) {
+	Log("CreateReadme (recovery): IH_DEC failed\n");
+    }
+
+    if (rvnode) {
+	free(rvnode);
+	rvnode = NULL;
+    }
+
+    return -1;
+}
+
+/**
+ * create a root dir for a volume that lacks one.
+ *
+ * @param[in] volHeader vol header for the volume
+ * @param[in] alinkH    ihandle for disk access for this volume group
+ * @param[in] vid       volume id we're dealing with
+ * @param[out] rootdir  populated with info about the new root dir
+ * @param[inout] maxunique  max uniquifier for all vnodes in the volume;
+ *                          updated to the new max unique if we create a new
+ *                          vnode
+ *
+ * @return operation status
+ *  @retval 0  success
+ *  @retval -1 error
+ */
+static int
+CreateRootDir(VolumeDiskData *volHeader, IHandle_t *alinkH, VolumeId vid,
+              struct DirSummary *rootdir, Unique *maxunique)
+{
+    FileVersion dv;
+    int decroot = 0, decreadme = 0;
+    AFSFid did, readmeid;
+    afs_fsize_t length;
+    Inode rootinode;
+    struct VnodeDiskObject *rootvnode = NULL;
+    struct acl_accessList *ACL;
+    Inode *ip;
+    afs_sfsize_t bytes;
+    struct VnodeEssence *vep;
+    Inode readmeinode;
+    time_t now = time(NULL);
+
+    if (!vnodeInfo[vLarge].vnodes && !vnodeInfo[vSmall].vnodes) {
+	Log("Not creating new root dir; volume appears to lack any vnodes\n");
+	goto error;
+    }
+
+    if (!vnodeInfo[vLarge].vnodes) {
+	/* We don't have any large vnodes in the volume; allocate room
+	 * for one so we can recreate the root dir */
+	vnodeInfo[vLarge].nVnodes = 1;
+	vnodeInfo[vLarge].vnodes = calloc(1, sizeof(struct VnodeEssence));
+	vnodeInfo[vLarge].inodes = calloc(1, sizeof(Inode));
+
+	assert(vnodeInfo[vLarge].vnodes);
+	assert(vnodeInfo[vLarge].inodes);
+    }
+
+    vep = &vnodeInfo[vLarge].vnodes[vnodeIdToBitNumber(1)];
+    ip = &vnodeInfo[vLarge].inodes[vnodeIdToBitNumber(1)];
+    if (vep->type != vNull) {
+	Log("Not creating new root dir; existing vnode 1 is non-null\n");
+	goto error;
+    }
+
+    if (CreateReadme(volHeader, alinkH, vid, maxunique, &readmeid, &readmeinode)) {
+	goto error;
+    }
+    decreadme = 1;
+
+    /* set the DV to a very high number, so it is unlikely that we collide
+     * with a cached DV */
+    dv = 1 << 30;
+
+    rootinode = IH_CREATE(alinkH, fileSysDevice, fileSysPath, 0, vid, 1, 1, dv);
+    if (!VALID_INO(rootinode)) {
+	Log("CreateRootDir: IH_CREATE failed\n");
+	goto error;
+    }
+    decroot = 1;
+
+    SetSalvageDirHandle(&rootdir->dirHandle, vid, fileSysDevice, rootinode);
+    did.Volume = vid;
+    did.Vnode = 1;
+    did.Unique = 1;
+    if (MakeDir(&rootdir->dirHandle, (afs_int32*)&did, (afs_int32*)&did)) {
+	Log("CreateRootDir: MakeDir failed\n");
+	goto error;
+    }
+    if (Create(&rootdir->dirHandle, "README.ROOTDIR", &readmeid)) {
+	Log("CreateRootDir: Create failed\n");
+	goto error;
+    }
+    DFlush();
+    length = Length(&rootdir->dirHandle);
+    DZap((void *)&rootdir->dirHandle);
+
+    /* create the new root dir vnode */
+    rootvnode = malloc(SIZEOF_LARGEDISKVNODE);
+    if (!rootvnode) {
+	Log("CreateRootDir: malloc failed\n");
+	goto error;
+    }
+
+    /* only give 'rl' permissions to 'system:administrators'. We do this to
+     * try to catch the attention of an administrator, that they should not
+     * be writing to this directory or continue to use it. */
+    ACL = VVnodeDiskACL(rootvnode);
+    ACL->size = sizeof(struct acl_accessList);
+    ACL->version = ACL_ACLVERSION;
+    ACL->total = 1;
+    ACL->positive = 1;
+    ACL->negative = 0;
+    ACL->entries[0].id = -204; /* system:administrators */
+    ACL->entries[0].rights = PRSFS_READ | PRSFS_LOOKUP;
+
+    rootvnode->type = vDirectory;
+    rootvnode->cloned = 0;
+    rootvnode->modeBits = 0777;
+    rootvnode->linkCount = 2;
+    VNDISK_SET_LEN(rootvnode, length);
+    rootvnode->uniquifier = 1;
+    rootvnode->dataVersion = dv;
+    VNDISK_SET_INO(rootvnode, rootinode);
+    rootvnode->unixModifyTime = rootvnode->serverModifyTime = now;
+    rootvnode->author = 0;
+    rootvnode->owner = 0;
+    rootvnode->parent = 0;
+    rootvnode->group = 0;
+    rootvnode->vnodeMagic = VnodeClassInfo[vLarge].magic;
+
+    /* write it out to disk */
+    bytes = IH_IWRITE(vnodeInfo[vLarge].handle,
+	      vnodeIndexOffset(&VnodeClassInfo[vLarge], 1),
+	      (char*)rootvnode, SIZEOF_LARGEDISKVNODE);
+
+    if (bytes != SIZEOF_LARGEDISKVNODE) {
+	/* just cast to int and don't worry about printing real 64-bit ints;
+	 * a large disk vnode isn't anywhere near the 32-bit limit */
+	Log("CreateRootDir: IH_IWRITE failed (%d/%d)\n", (int)bytes,
+	    (int)SIZEOF_LARGEDISKVNODE);
+	goto error;
+    }
+
+    /* update VnodeEssence for the new root vnode */
+    vnodeInfo[vLarge].nAllocatedVnodes++;
+    vep->count = 0;
+    vep->blockCount = nBlocks(length);
+    vnodeInfo[vLarge].volumeBlockCount += vep->blockCount;
+    vep->parent = rootvnode->parent;
+    vep->unique = rootvnode->uniquifier;
+    vep->modeBits = rootvnode->modeBits;
+    vep->InodeNumber = VNDISK_GET_INO(rootvnode);
+    vep->type = rootvnode->type;
+    vep->author = rootvnode->author;
+    vep->owner = rootvnode->owner;
+    vep->group = rootvnode->group;
+
+    free(rootvnode);
+    rootvnode = NULL;
+
+    vep->claimed = 0;
+    vep->changed = 0;
+    vep->salvaged = 1;
+    vep->todelete = 0;
+
+    /* update DirSummary for the new root vnode */
+    rootdir->vnodeNumber = 1;
+    rootdir->unique = 1;
+    rootdir->haveDot = 1;
+    rootdir->haveDotDot = 1;
+    rootdir->rwVid = vid;
+    rootdir->copied = 0;
+    rootdir->parent = 0;
+    rootdir->name = strdup(".");
+    rootdir->vname = volHeader->name;
+    rootdir->ds_linkH = alinkH;
+
+    *ip = rootinode;
+
+    return 0;
+
+ error:
+    if (decroot && IH_DEC(alinkH, rootinode, vid)) {
+	Log("CreateRootDir (recovery): IH_DEC (root) failed\n");
+    }
+    if (decreadme && IH_DEC(alinkH, readmeinode, vid)) {
+	Log("CreateRootDir (recovery): IH_DEC (readme) failed\n");
+    }
+    if (rootvnode) {
+	free(rootvnode);
+	rootvnode = NULL;
+    }
+    return -1;
+}
+
 int
 SalvageVolume(register struct InodeSummary *rwIsp, IHandle_t * alinkH)
 {
@@ -3482,6 +3851,7 @@
     VnodeId LFVnode, ThisVnode;
     Unique LFUnique, ThisUnique;
     char npath[128];
+    int newrootdir = 0;
 
     vid = rwIsp->volSummary->header.id;
     IH_INIT(h, fileSysDevice, vid, rwIsp->volSummary->header.volumeInfo);
@@ -3511,6 +3881,18 @@
 	return 0;
     }
 
+    if (!rootdirfound && (orphans == ORPH_ATTACH) && !Testing) {
+
+	Log("Cannot find root directory for volume %u; attempting to create "
+	    "a new one\n", vid);
+
+	code = CreateRootDir(&volHeader, alinkH, vid, &rootdir, &maxunique);
+	if (code == 0) {
+	    rootdirfound = 1;
+	    newrootdir = 1;
+	}
+    }
+
     /* Parse each vnode looking for orphaned vnodes and
      * connect them to the tree as orphaned (if requested).
      */
@@ -3532,8 +3914,20 @@
 	     */
 	    if (class == vLarge) {	/* directory vnode */
 		pv = vnodeIdToBitNumber(vep->parent);
-		if (vnodeInfo[vLarge].vnodes[pv].unique != 0)
-		    vnodeInfo[vLarge].vnodes[pv].count++;
+		if (vnodeInfo[vLarge].vnodes[pv].unique != 0) {
+		    if (vep->parent == 1 && newrootdir) {
+			/* this vnode's parent was the volume root, and
+			 * we just created the volume root. So, the parent
+			 * dir didn't exist during JudgeEntry, so the link
+			 * count was not inc'd there, so don't dec it here.
+			 */
+
+			 /* noop */
+
+		    } else {
+			vnodeInfo[vLarge].vnodes[pv].count++;
+		    }
+		}
 	    }
 
 	    if (!rootdirfound)
@@ -3731,6 +4125,12 @@
 	volHeader.uniquifier = (maxunique + 1 + 2000);
     }
 
+    if (newrootdir) {
+	Log("*** WARNING: Root directory recreated, but volume is fragile! "
+	    "Only use this salvaged volume to copy data to another volume; "
+	    "do not continue to use this volume (%u) as-is.\n", vid);
+    }
+
     /* Turn off the inUse bit; the volume's been salvaged! */
     volHeader.inUse = 0;	/* clear flag indicating inUse@last crash */
     volHeader.needsSalvaged = 0;	/* clear 'damaged' flag */
diff -Naur openafs_1.4.14.orig/src/vol/volume.c openafs_1.4.14/src/vol/volume.c
--- openafs_1.4.14.orig/src/vol/volume.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/vol/volume.c	2011-03-29 08:33:49.104185344 +0200
@@ -979,6 +979,20 @@
 	    V_inUse(vp) = 1;
 	    V_offlineMessage(vp)[0] = '\0';
 	}
+	if (!V_inUse(vp)) {
+	    *ec = VNOVOL;
+	    /* mimic e.g. GetVolume errors */
+	    if (!V_blessed(vp))
+		Log("Volume %u offline: not blessed\n", V_id(vp));
+	    else if (!V_inService(vp))
+		Log("Volume %u offline: not in service\n", V_id(vp));
+	    else {
+		Log("Volume %u offline: needs salvage\n", V_id(vp));
+		*ec = VOFFLINE;
+	    }
+	    VPutVolume_r(vp);
+	    vp = NULL;
+	}
     }
 
     return vp;
diff -Naur openafs_1.4.14.orig/src/volser/dumpstuff.c openafs_1.4.14/src/volser/dumpstuff.c
--- openafs_1.4.14.orig/src/volser/dumpstuff.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/volser/dumpstuff.c	2011-03-29 08:33:49.236179917 +0200
@@ -45,6 +45,7 @@
 #include "dump.h"
 #include <afs/fssync.h>
 #include <afs/acl.h>
+#include <afs/com_err.h>
 #include "volser.h"
 #include "volint.h"
 
diff -Naur openafs_1.4.14.orig/src/volser/volprocs.c openafs_1.4.14/src/volser/volprocs.c
--- openafs_1.4.14.orig/src/volser/volprocs.c	2010-12-17 16:58:42.000000000 +0100
+++ openafs_1.4.14/src/volser/volprocs.c	2011-03-29 08:33:49.236179917 +0200
@@ -95,7 +95,7 @@
 
 /* this call unlocks all of the partition locks we've set */
 int 
-VPFullUnlock()
+VPFullUnlock_r(void)
 {
     register struct DiskPartition64 *tp;
     for (tp = DiskPartitionList; tp; tp = tp->next) {
@@ -107,6 +107,16 @@
     return 0;
 }
 
+int
+VPFullUnlock(void)
+{
+    int code;
+    VOL_LOCK;
+    code = VPFullUnlock_r();
+    VOL_UNLOCK;
+    return code;
+}
+
 /* get partition id from a name */
 afs_int32
 PartitionID(char *aname)
@@ -2642,7 +2652,7 @@
 {
     transDebugInfo *pntr;
     afs_int32 allocSize = 50;
-    struct volser_trans *tt, *allTrans;
+    struct volser_trans *tt, *nt, *allTrans;
 
     transInfo->transDebugEntries_val =
 	(transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
@@ -2655,9 +2665,8 @@
     allTrans = TransList();
     if (allTrans == (struct volser_trans *)0)
 	goto done;		/*no active transactions */
-    for (tt = allTrans; tt; tt = tt->next) {	/*copy relevant info into pntr */
-        THOLD(tt);  /* do not delete tt while copying info */
-        VTRANS_UNLOCK;
+    for (tt = allTrans; tt; tt = nt) {	/*copy relevant info into pntr */
+	nt = tt->next;
         VTRANS_OBJ_LOCK(tt);
 	pntr->tid = tt->tid;
 	pntr->time = tt->time;
@@ -2694,8 +2703,6 @@
 	    /*set pntr to right position */
 	}
 
-        TRELE(tt);
-        VTRANS_LOCK;
     }
 done:
     VTRANS_UNLOCK;
