Common subdirectories: linux-2.2.1/include/linux/byteorder and linux/include/linux/byteorder
Common subdirectories: linux-2.2.1/include/linux/lockd and linux/include/linux/lockd
Common subdirectories: linux-2.2.1/include/linux/nfsd and linux/include/linux/nfsd
Common subdirectories: linux-2.2.1/include/linux/sunrpc and linux/include/linux/sunrpc
diff -u -X exclude linux-2.2.1/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- linux-2.2.1/include/linux/nfsd/nfsfh.h	Thu Oct  8 21:32:12 1998
+++ linux/include/linux/nfsd/nfsfh.h	Mon Feb 22 21:13:06 1999
@@ -33,6 +33,7 @@
 	__u32		fb_dev;		/* our device */
 	__u32		fb_xdev;
 	__u32		fb_xino;
+	__u32		fb_generation;
 };
 
 #define NFS_FH_PADDING		(NFS_FHSIZE - sizeof(struct nfs_fhbase))
@@ -47,6 +48,7 @@
 #define fh_dev			fh_base.fb_dev
 #define fh_xdev			fh_base.fb_xdev
 #define fh_xino			fh_base.fb_xino
+#define fh_generation		fh_base.fb_generation
 
 #ifdef __KERNEL__
 
@@ -106,6 +108,9 @@
 void	nfsd_fh_flush(kdev_t);
 void	nfsd_fh_init(void);
 void	nfsd_fh_free(void);
+void	expire_all(void);
+void	expire_by_dentry(struct dentry *);
+
 
 static __inline__ struct svc_fh *
 fh_copy(struct svc_fh *dst, struct svc_fh *src)
@@ -178,32 +183,9 @@
 }
 
 /*
- * Release an inode
+ * This is a long term cache to help find renamed files.
  */
-#if 0
-#define fh_put(fhp)	__fh_put(fhp, __FILE__, __LINE__)
-
-static inline void
-__fh_put(struct svc_fh *fhp, char *file, int line)
-{
-	struct dentry	*dentry;
-
-	if (!fhp->fh_dverified)
-		return;
-
-	dentry = fhp->fh_dentry;
-	if (!dentry->d_count) {
-		printk("nfsd: trying to free free dentry in %s:%d\n"
-		       "      file %s/%s\n",
-		       file, line,
-		       dentry->d_parent->d_name.name, dentry->d_name.name);
-	} else {
-		fh_unlock(fhp);
-		fhp->fh_dverified = 0;
-		dput(dentry);
-	}
-}
-#endif
+void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino);
 
 #endif /* __KERNEL__ */
 
Common subdirectories: linux-2.2.1/fs/adfs and linux/fs/adfs
Common subdirectories: linux-2.2.1/fs/affs and linux/fs/affs
Common subdirectories: linux-2.2.1/fs/autofs and linux/fs/autofs
Common subdirectories: linux-2.2.1/fs/coda and linux/fs/coda
Common subdirectories: linux-2.2.1/fs/devpts and linux/fs/devpts
Common subdirectories: linux-2.2.1/fs/ext2 and linux/fs/ext2
Common subdirectories: linux-2.2.1/fs/fat and linux/fs/fat
Common subdirectories: linux-2.2.1/fs/hfs and linux/fs/hfs
Common subdirectories: linux-2.2.1/fs/hpfs and linux/fs/hpfs
Common subdirectories: linux-2.2.1/fs/isofs and linux/fs/isofs
Common subdirectories: linux-2.2.1/fs/lockd and linux/fs/lockd
Common subdirectories: linux-2.2.1/fs/minix and linux/fs/minix
Common subdirectories: linux-2.2.1/fs/msdos and linux/fs/msdos
Common subdirectories: linux-2.2.1/fs/ncpfs and linux/fs/ncpfs
Common subdirectories: linux-2.2.1/fs/nfs and linux/fs/nfs
Common subdirectories: linux-2.2.1/fs/nfsd and linux/fs/nfsd
Common subdirectories: linux-2.2.1/fs/nls and linux/fs/nls
Common subdirectories: linux-2.2.1/fs/ntfs and linux/fs/ntfs
Common subdirectories: linux-2.2.1/fs/proc and linux/fs/proc
Common subdirectories: linux-2.2.1/fs/qnx4 and linux/fs/qnx4
Common subdirectories: linux-2.2.1/fs/romfs and linux/fs/romfs
Common subdirectories: linux-2.2.1/fs/smbfs and linux/fs/smbfs
Common subdirectories: linux-2.2.1/fs/sysv and linux/fs/sysv
Common subdirectories: linux-2.2.1/fs/ufs and linux/fs/ufs
Common subdirectories: linux-2.2.1/fs/umsdos and linux/fs/umsdos
Common subdirectories: linux-2.2.1/fs/vfat and linux/fs/vfat
diff -u -X exclude linux-2.2.1/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux-2.2.1/fs/nfs/dir.c	Tue Jan 19 11:22:18 1999
+++ linux/fs/nfs/dir.c	Mon Feb 22 19:43:46 1999
@@ -1158,8 +1158,9 @@
 	 */
 	if (old_dentry->d_count > 1) {
 		nfs_wb_all(old_inode);
-		shrink_dcache_parent(old_dentry);
+/*		shrink_dcache_parent(old_dentry); FIXME */
 	}
+	goto do_rename;
 
 	/*
 	 * Now check the use counts ... we can't safely do the
Only in linux/fs/nfs: nfs3proc.c
diff -u -X exclude linux-2.2.1/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- linux-2.2.1/fs/nfsd/nfsfh.c	Tue Jan 19 11:22:18 1999
+++ linux/fs/nfsd/nfsfh.c	Tue Feb 23 11:08:09 1999
@@ -4,6 +4,7 @@
  * NFS server file handle treatment.
  *
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Portions Copyright (C) 1999 G. Allen Morris III <gam3@acm.org>
  */
 
 #include <linux/sched.h>
@@ -20,6 +21,7 @@
 #define NFSDDBG_FACILITY		NFSDDBG_FH
 #define NFSD_PARANOIA 1
 /* #define NFSD_DEBUG_VERBOSE 1 */
+/* #define NFSD_DEBUG_VERY_VERBOSE 1 */
 
 extern unsigned long max_mapnr;
 
@@ -49,15 +51,16 @@
 static int nfsd_nr_fixups = 0;
 static int nfsd_nr_paths = 0;
 #define NFSD_MAX_PATHS 500
-#define NFSD_MAX_FIXUPAGE 60*HZ
+#define NFSD_MAX_FIXUPS 500
+#define NFSD_MAX_FIXUP_AGE 30*HZ
 
 struct nfsd_fixup {
 	struct list_head lru;
-	ino_t	dir;
+	unsigned long reftime;
+	ino_t	dirino;
 	ino_t	ino;
 	kdev_t	dev;
-	struct dentry *dentry;
-	unsigned long reftime;
+	ino_t	new_dirino;
 };
 
 struct nfsd_path {
@@ -69,7 +72,8 @@
 	char	name[1];
 };
 
-static struct nfsd_fixup * find_cached_lookup(kdev_t dev, ino_t dir, ino_t ino)
+static struct nfsd_fixup *
+find_cached_lookup(kdev_t dev, ino_t dirino, ino_t ino)
 {
 	struct list_head *tmp = fixup_head.next;
 
@@ -77,32 +81,43 @@
 		struct nfsd_fixup *fp;
 
 		fp = list_entry(tmp, struct nfsd_fixup, lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("fixup %lu %lu, %lu %lu %s %s\n",
+        fp->ino, ino,
+	fp->dirino, dirino,
+	kdevname(fp->dev), kdevname(dev));
+#endif
 		if (fp->ino != ino)
 			continue;
-		if (fp->dir != dir)
+		if (fp->dirino != dirino)
 			continue;
 		if (fp->dev != dev)
 			continue;
+		fp->reftime = jiffies;	
 		list_del(tmp);
 		list_add(tmp, &fixup_head);
-		fp->reftime = jiffies;
 		return fp;
 	}
 	return NULL;
 }
 
 /*
- * Save the dentry pointer from a successful lookup.
+ * Save the dirino from a rename.
  */
-static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh)
+void
+add_to_rename_cache(ino_t new_dirino,
+                    kdev_t dev, ino_t dirino, ino_t ino)
 {
 	struct nfsd_fixup *fp;
 
-	fp = find_cached_lookup(u32_to_kdev_t(fh->fh_dev), 
-				u32_to_ino_t(fh->fh_dirino),
-				u32_to_ino_t(fh->fh_ino));
+	if (dirino == new_dirino)
+		return;
+
+	fp = find_cached_lookup(dev, 
+				dirino,
+				ino);
 	if (fp) {
-		fp->dentry = dentry;
+		fp->new_dirino = new_dirino;
 		return;
 	}
 
@@ -113,19 +128,30 @@
 	 */
 	fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL);
 	if (fp) {
-		fp->dir = u32_to_kdev_t(fh->fh_dirino);
-		fp->ino = u32_to_ino_t(fh->fh_ino);
-		fp->dev = u32_to_ino_t(fh->fh_dev);
-		fp->dentry = dentry;
-		fp->reftime = jiffies;
+		fp->dirino = dirino;
+		fp->ino = ino;
+		fp->dev = dev;
+		fp->new_dirino = new_dirino;
 		list_add(&fp->lru, &fixup_head);
 		nfsd_nr_fixups++;
 	}
 }
 
+/*
+ * Save the dentry pointer from a successful lookup.
+ */
+
 static void free_fixup_entry(struct nfsd_fixup *fp)
 {
 	list_del(&fp->lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("free_rename_entry: %lu->%lu %lu/%s\n",
+		fp->dirino,
+		fp->new_dirino,
+		fp->ino,
+		kdevname(fp->dev),
+		(jiffies - fp->reftime));
+#endif
 	kfree(fp);
 	nfsd_nr_fixups--;
 }
@@ -210,9 +236,9 @@
 	if (new) {
 		new->users = 0;	
 		new->reftime = jiffies;	
-		new->ino = inode->i_ino;	
-		new->dev = inode->i_dev;	
-		result = copy_path(new->name, dentry, len);	
+		new->ino = inode->i_ino;
+		new->dev = inode->i_dev;
+		result = copy_path(new->name, dentry, len);
 		if (!result)
 			goto retry;
 		list_add(&new->lru, &path_inuse);
@@ -299,8 +325,8 @@
 	int result = 0;
 
 	buf->sequence++;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("filldir_one: seq=%d, ino=%lu, name=%s\n", buf->sequence, ino, name);
 #endif
 	if (buf->sequence == 2) {
 		buf->dirino = ino;
@@ -309,7 +335,7 @@
 	if (dirent->ino == ino) {
 		dirent->len = len;
 		memcpy(dirent->name, name, len);
-		dirent->name[len] = 0;
+		dirent->name[len] = '\0';
 		buf->found = 1;
 		result = -1;
 	}
@@ -519,7 +545,8 @@
 	struct dentry *dentry = empty->dentry;
 
 #ifdef NFSD_DEBUG_VERBOSE
-printk("expire_fhe: expiring %s/%s, d_count=%d, ino=%ld\n",
+printk("expire_fhe: expiring %s %s/%s, d_count=%d, ino=%lu\n",
+(cache == NFSD_FILE_CACHE) ? "file" : "dir",
 dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino);
 #endif
 	empty->dentry = NULL;	/* no dentry */
@@ -574,11 +601,10 @@
  */
 static void expire_old(int cache, int age)
 {
-	struct list_head *tmp;
 	struct fh_entry *fhe;
 	int i;
 
-#ifdef NFSD_DEBUG_VERBOSE
+#ifdef NFSD_DEBUG_VERY_VERBOSE
 printk("expire_old: expiring %s older than %d\n",
 (cache == NFSD_FILE_CACHE) ? "file" : "dir", age);
 #endif
@@ -591,12 +617,12 @@
 	}
 
 	/*
-	 * Remove old entries from the patch-up cache.
+	 * Trim the fixup cache ...
 	 */
-	while ((tmp = fixup_head.prev) != &fixup_head) {
+	while (nfsd_nr_fixups > NFSD_MAX_FIXUPS) {
 		struct nfsd_fixup *fp;
-		fp = list_entry(tmp, struct nfsd_fixup, lru);
-		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUPAGE)
+		fp = list_entry(fixup_head.prev, struct nfsd_fixup, lru);
+		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUP_AGE)
 			break;
 		free_fixup_entry(fp);
 	}
@@ -749,6 +775,18 @@
 	return dentry;
 }
 
+static u32
+get_generation_number(struct inode *inode)
+{
+	u32 ret = 0;
+
+/* FIXME: this should be generalized and use flag in s_type->flags */
+	if (inode && !strcmp("ext2", inode->i_sb->s_type->name)) {
+		ret = ino_t_to_u32(inode->u.ext2_i.i_version);
+	}
+	return ret;
+}
+
 /*
  * Look for an entry in the file cache matching the dentry pointer,
  * and verify that the (dev, inode) numbers are correct. If found,
@@ -756,6 +794,8 @@
  */
 static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh)
 {
+/* FIXME: this must use the dev/ino/dir_ino triple. */ 
+#if 0
 	struct fh_entry * fhe;
 
 	fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
@@ -793,6 +833,7 @@
 		return dentry;
 	}
 out:
+#endif
 	return NULL;
 }
 
@@ -841,13 +882,12 @@
 	dentry = NULL;
 out:
 	return dentry;
-
 }
 
 /*
  * Search the fix-up list for a dentry from a prior lookup.
  */
-static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
+static ino_t nfsd_cached_lookup(struct knfs_fh *fh)
 {
 	struct nfsd_fixup *fp;
 
@@ -855,8 +895,8 @@
 				u32_to_ino_t(fh->fh_dirino),
 				u32_to_ino_t(fh->fh_ino));
 	if (fp)
-		return fp->dentry;
-	return NULL;
+		return fp->new_dirino;
+	return 0;
 }
 
 /*
@@ -887,8 +927,12 @@
 static struct dentry *
 find_fh_dentry(struct knfs_fh *fh)
 {
+	struct super_block *sb;
 	struct dentry *dentry, *parent;
+	struct inode * inode;
+	struct list_head *lst;
 	int looked_up = 0, retry = 0;
+	ino_t dirino;
 
 	/*
 	 * Stage 1: Look for the dentry in the short-term fhcache.
@@ -898,50 +942,67 @@
 		nfsdstats.fh_cached++;
 		goto out;
 	}
-
 	/*
-	 * Stage 2: Attempt to validate the dentry in the file handle.
+	 * Stage 2: Attempt to find the inode.
 	 */
-	dentry = fh->fh_dcookie;
+	sb = get_super(fh->fh_dev);
+	if (NULL == sb) {
+		printk("find_fh_dentry: No SuperBlock for device %s.",
+		       kdevname(fh->fh_dev));
+		dentry = NULL;
+		goto out;
+	}
+
+	dirino = u32_to_ino_t(fh->fh_dirino);
+	inode = iget(sb, fh->fh_ino);
 recheck:
-	if (nfsd_d_validate(dentry)) {
-		struct inode * dir = dentry->d_parent->d_inode;
+	if (!inode) {
+		dprintk(": No inode found.\n");
+		goto out_three;
+	}
+	for (lst = inode->i_dentry.next;
+	     lst != &inode->i_dentry;
+	     lst = lst->next) {
+		dentry = list_entry(lst, struct dentry, d_alias);
+
+/* if we are looking up a directory then we don't need the parent! */
+		if (!dentry ||
+		    !dentry->d_parent ||
+		    !dentry->d_parent->d_inode) {
+printk("find_fh_dentry: Found a useless inode %lu\n", inode->i_ino);
+			continue;
+		}
+		if (dentry->d_parent->d_inode->i_ino != dirino)
+			continue;
 
-		if (dir->i_ino == u32_to_ino_t(fh->fh_dirino) && 
-		    dir->i_dev == u32_to_kdev_t(fh->fh_dev)) {
-			struct inode * inode = dentry->d_inode;
-			/*
-			 * NFS file handles must always have an inode,
-			 * so we won't accept a negative dentry.
-			 */
-			if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
-				dget(dentry);
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: validated %s/%s, ino=%ld\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino);
-#endif
-				if (!retry)
-					nfsdstats.fh_valid++;
-				else {
-					nfsdstats.fh_fixup++;
+		dget(dentry);
+		iput(inode);
 #ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: retried validation successful\n");
+		printk("find_fh_dentry: Found%s %s/%s filehandle dirino = %lu, %lu\n",
+		       retry ? " Renamed" : "",
+		       dentry->d_parent->d_name.name,
+		       dentry->d_name.name,
+		       dentry->d_parent->d_inode->i_ino,
+		       dirino);
 #endif
-				}
-				goto out;
-			}
-		}
-	}
+		goto out;
+	} /* for inode->i_dentry */
 
 	/*
-	 * Before proceeding to a lookup, check whether we cached a
-	 * prior lookup. If so, try to validate that dentry ...
+	 * Before proceeding to a lookup, check for a rename
 	 */
-	if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) {
+	if (!retry && (dirino = nfsd_cached_lookup(fh))) {
+		dprintk("find_fh_dentry: retry with %lu\n", dirino);
 		retry = 1;
 		goto recheck;
 	}
 
+	iput(inode);
+
+	dprintk("find_fh_dentry: dirino not found %lu\n", dirino);
+
+out_three:
+
 	/*
 	 * Stage 3: Look up the dentry based on the inode and parent inode
 	 * numbers. This should work for all Unix-like filesystems.
@@ -954,7 +1015,7 @@
 		struct inode * inode = dentry->d_inode;
 #ifdef NFSD_DEBUG_VERBOSE
 printk("find_fh_dentry: looked up %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 		if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
 			nfsdstats.fh_lookup++;
@@ -962,7 +1023,7 @@
 		}
 #ifdef NFSD_PARANOIA
 printk("find_fh_dentry: %s/%s lookup mismatch!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 		dput(dentry);
 	}
@@ -983,30 +1044,49 @@
 	}
 
 	/*
-	 * Stage 5: Search the whole volume.
+	 * Stage 5: Search the whole volume, Yea Right.
 	 */
 #ifdef NFSD_PARANOIA
-printk("find_fh_dentry: %s, %u/%u not found -- need full search!\n",
-kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_dirino, fh->fh_ino);
+printk("find_fh_dentry: %s/%u dir/%u not found!\n",
+       kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino, fh->fh_dirino);
 #endif
 	dentry = NULL;
 	nfsdstats.fh_stale++;
 	
 out:
-	if (looked_up && dentry) {
-		add_to_lookup_cache(dentry, fh);
-	}
 
 	/*
 	 * Perform any needed housekeeping ...
-	 * N.B. move this into one of the daemons ...
 	 */
+	expire_all();
+	return dentry;
+}
+
+void
+expire_all(void)
+{
 	if (time_after_eq(jiffies, nfsd_next_expire)) {
 		expire_old(NFSD_FILE_CACHE,  5*HZ);
 		expire_old(NFSD_DIR_CACHE , 60*HZ);
 		nfsd_next_expire = jiffies + 5*HZ;
 	}
-	return dentry;
+}
+
+/* 
+ * Free cache after unlink.
+ * FIXME: (gam3) only do files now, should directories also be done?
+ */
+void
+expire_by_dentry(struct dentry *dentry)
+{
+	struct fh_entry *fhe;
+
+	fhe = find_fhe(dentry, NFSD_FILE_CACHE, NULL);
+	if (fhe)
+		expire_fhe(fhe, NFSD_FILE_CACHE);
+	fhe = find_fhe(dentry, NFSD_DIR_CACHE, NULL);
+	if (fhe)
+		expire_fhe(fhe, NFSD_DIR_CACHE);
 }
 
 /*
@@ -1024,8 +1104,12 @@
 	struct inode	*inode;
 	u32		error = 0;
 
-	dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n",
-		fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
+	dprintk("nfsd: fh_verify(exp %s/%u file (%s/%u dir %u)\n",
+		kdevname(fh->fh_xdev),
+		fh->fh_xino,
+		kdevname(fh->fh_dev),
+		fh->fh_ino,
+		fh->fh_dirino);
 
 	if (fhp->fh_dverified)
 		goto check_type;
@@ -1034,8 +1118,8 @@
 	 */
 	error = nfserr_stale;
 	exp = exp_get(rqstp->rq_client,
-			u32_to_kdev_t(fh->fh_xdev),
-			u32_to_ino_t(fh->fh_xino));
+		      u32_to_kdev_t(fh->fh_xdev),
+		      u32_to_ino_t(fh->fh_xino));
 	if (!exp) /* export entry revoked */
 		goto out;
 
@@ -1057,8 +1141,13 @@
 	 */
 	error = nfserr_noent;
 	dentry = find_fh_dentry(fh);
-	if (!dentry)
+	if (!dentry) {
 		goto out;
+	}
+	if (IS_ERR(dentry)) {
+		error = nfserrno(-PTR_ERR(dentry));
+		goto out;
+	}
 
 	/*
 	 * Note:  it's possible the returned dentry won't be the one in the
@@ -1080,6 +1169,21 @@
 check_type:
 	dentry = fhp->fh_dentry;
 	inode = dentry->d_inode;
+	error = nfserr_stale;
+/* is to keep from breaking the nfs filehandles until june */
+
+#define FIXME_IN_JUNE_1999 1
+
+	if (get_generation_number(inode) != fh->fh_generation) {
+		dprintk("fh_verify: Bad version %u %lu %u\n",
+			inode->i_ino,
+			get_generation_number(inode),
+			fh->fh_generation);
+#ifdef  FIXME_IN_JUNE_1999
+	if (fh->fh_dcookie == 0xfeebbaca)
+#endif
+		goto out;
+	}
 	exp = fhp->fh_export;
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
@@ -1095,8 +1199,8 @@
 	 */
 	error = 0;
 	if (fh->fh_dev != fh->fh_xdev) {
-		printk("fh_verify: Security: export on other device"
-		       " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+		printk("fh_verify: Security: export on other device (%s, %s).\n",
+		       kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
 		error = nfserr_stale;
 	} else if (exp->ex_dentry != dentry) {
 		struct dentry *tdentry = dentry;
@@ -1106,13 +1210,13 @@
 			if (exp->ex_dentry == tdentry)
 				break;
 			/* executable only by root and we can't be root */
-			if (current->fsuid &&
-			    !(tdentry->d_inode->i_uid  &&
-			        (tdentry->d_inode->i_mode & S_IXUSR)) &&
-			    !(tdentry->d_inode->i_gid &&
-			        (tdentry->d_inode->i_mode & S_IXGRP)) &&
-			    !(tdentry->d_inode->i_mode & S_IXOTH) && 
-			    (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
+			if (current->fsuid
+			    && !(tdentry->d_inode->i_uid
+			         && (tdentry->d_inode->i_mode & S_IXUSR))
+			    && !(tdentry->d_inode->i_gid
+				 && (tdentry->d_inode->i_mode & S_IXGRP))
+			    && !(tdentry->d_inode->i_mode & S_IXOTH)
+			    && (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
 				error = nfserr_stale;
 dprintk("fh_verify: no root_squashed access.\n");
 			}
@@ -1168,9 +1272,10 @@
 	}
 	fh_init(fhp);
 
-	fhp->fh_handle.fh_dcookie = dentry;
+	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
+		fhp->fh_handle.fh_generation = get_generation_number(inode);
 	}
 	fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
 	fhp->fh_handle.fh_dev	 = kdev_t_to_u32(parent->d_inode->i_dev);
@@ -1202,6 +1307,7 @@
 	if (!inode)
 		goto out_negative;
 	fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
+	fhp->fh_handle.fh_generation = get_generation_number(inode);
 out:
 	return;
 
@@ -1317,7 +1423,7 @@
 }
 
 /*
- * Free the dentry and path caches.
+ * Free the rename and path caches.
  */
 void nfsd_fh_free(void)
 {
diff -u -X exclude linux-2.2.1/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- linux-2.2.1/fs/nfsd/nfssvc.c	Fri Jan  1 23:03:09 1999
+++ linux/fs/nfsd/nfssvc.c	Mon Feb 22 19:43:48 1999
@@ -5,7 +5,7 @@
  *
  * Authors:	Olaf Kirch (okir@monad.swb.de)
  *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
  */
 
 #define __NO_VERSION__
@@ -72,16 +72,17 @@
 	if (serv == NULL)
 		goto out;
 
-	error = svc_makesock(serv, IPPROTO_UDP, port);
-	if (error < 0)
-		goto failure;
-
 #if 0	/* Don't even pretend that TCP works. It doesn't. */
 	error = svc_makesock(serv, IPPROTO_TCP, port);
 	if (error < 0)
 		goto failure;
 #endif
 
+	error = svc_makesock(serv, IPPROTO_UDP, port);
+	if (error < 0)
+		goto failure;
+
+
 	while (nrservs--) {
 		error = svc_create_thread(nfsd, serv);
 		if (error < 0)
@@ -101,7 +102,7 @@
 nfsd(struct svc_rqst *rqstp)
 {
 	struct svc_serv	*serv = rqstp->rq_server;
-	int		oldumask, err;
+	int		oldumask, err, first = 0;
 
 	/* Lock module and set up kernel thread */
 	MOD_INC_USE_COUNT;
@@ -115,8 +116,10 @@
 
 	oldumask = current->fs->umask;		/* Set umask to 0.  */
 	current->fs->umask = 0;
-	if (!nfsd_active++)
+	if (!nfsd_active++) {
 		nfssvc_boot = xtime;		/* record boot time */
+		first = 1;
+	}
 	lockd_up();				/* start lockd */
 
 	/*
@@ -133,8 +136,14 @@
 		 * Find a socket with data available and call its
 		 * recvfrom routine.
 		 */
-		while ((err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
-			;
+		while ((err = svc_recv(serv, rqstp,
+		        first?5*HZ:MAX_SCHEDULE_TIMEOUT)) == -EAGAIN) {
+			if (first && 1) {
+				exp_readlock();
+				expire_all();
+				exp_unlock();
+			}
+		}
 		if (err < 0)
 			break;
 
diff -u -X exclude linux-2.2.1/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux-2.2.1/fs/nfsd/vfs.c	Mon Feb 22 19:36:43 1999
+++ linux/fs/nfsd/vfs.c	Mon Feb 22 21:26:44 1999
@@ -21,7 +21,6 @@
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/ext2_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -554,7 +553,7 @@
 	/* clear setuid/setgid flag after write */
 	if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
 		struct iattr	ia;
-		kernel_cap_t	saved_cap;
+		kernel_cap_t	saved_cap = 0;
 
 		ia.ia_valid = ATTR_MODE;
 		ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
@@ -658,10 +657,6 @@
 		if (IS_ERR(dchild))
 			goto out_nfserr;
 		fh_compose(resfhp, fhp->fh_export, dchild);
-		/* Lock the parent and check for errors ... */
-		err = fh_lock_parent(fhp, dchild);
-		if (err)
-			goto out;
 	} else {
 		dchild = resfhp->fh_dentry;
 		if (!fhp->fh_locked)
@@ -670,6 +665,15 @@
 				dentry->d_parent->d_name.name,
 				dentry->d_name.name);
 	}
+	err = nfserr_exist;
+	if (dchild->d_inode)
+		goto out;
+	if (!fhp->fh_locked) {
+		/* Lock the parent and check for errors ... */
+		err = fh_lock_parent(fhp, dchild);
+		if (err)
+			goto out;
+	}
 	/*
 	 * Make sure the child dentry is still negative ...
 	 */
@@ -695,8 +699,7 @@
 	case S_IFCHR:
 	case S_IFBLK:
 		/* The client is _NOT_ required to do security enforcement */
-		if(!capable(CAP_SYS_ADMIN))
-		{
+		if(!capable(CAP_SYS_ADMIN)) {
 			err = -EPERM;
 			goto out;
 		}
@@ -759,7 +762,7 @@
 	struct inode	*inode;
 	struct iattr	newattrs;
 	int		err;
-	kernel_cap_t	saved_cap;
+	kernel_cap_t	saved_cap = 0;
 
 	err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
 	if (err)
@@ -899,6 +902,7 @@
 	/* Compose the fh so the dentry will be freed ... */
 out_compose:
 	fh_compose(resfhp, fhp->fh_export, dnew);
+
 out:
 	return err;
 
@@ -1091,6 +1095,15 @@
 	DQUOT_DROP(tdir);
 
 	nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
+
+	if (!err && odentry->d_inode) {
+		add_to_rename_cache(tdir->i_ino,
+				    odentry->d_inode->i_dev,
+				    fdir->i_ino,
+				    odentry->d_inode->i_ino);
+	} else {
+		printk(": no inode in rename or err: %d.\n", err);
+	}
 	dput(ndentry);
 
 out_dput_old:
@@ -1132,7 +1145,6 @@
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
-
 	if (!rdentry->d_inode) {
 		dput(rdentry);
 		err = nfserr_noent;
@@ -1151,7 +1163,7 @@
 		fh_unlock(fhp);
 
 		dput(rdentry);
-
+		expire_by_dentry(rdentry);
 	} else {
 		/* It's RMDIR */
 		/* See comments in fs/namei.c:do_rmdir */
@@ -1179,6 +1191,7 @@
 		goto out_nfserr;
 	if (EX_ISSYNC(fhp->fh_export))
 		write_inode_now(dirp);
+
 out:
 	return err;
 
@@ -1310,7 +1323,7 @@
 {
 	struct inode	*inode = dentry->d_inode;
 	int		err;
-	kernel_cap_t	saved_cap;
+	kernel_cap_t	saved_cap = 0;
 
 	if (acc == MAY_NOP)
 		return 0;
@@ -1330,7 +1343,7 @@
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 #ifndef CONFIG_NFSD_SUN
-        if (dentry->d_mounts != dentry) {
+	if (dentry->d_mounts != dentry) {
 		return nfserr_perm;
 	}
 #endif
diff -u -X exclude linux-2.2.1/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- linux-2.2.1/fs/ext2/ialloc.c	Thu Nov 12 08:32:58 1998
+++ linux/fs/ext2/ialloc.c	Mon Feb 22 19:43:48 1999
@@ -34,6 +34,7 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/quotaops.h>
+#include <linux/random.h>
 
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
@@ -268,15 +269,16 @@
 }
 
 /*
- * This function increments the inode version number
+ * This function sets the inode version number
  *
- * This may be used one day by the NFS server
+ * This is used by the NFS server
  */
-static void inc_inode_version (struct inode * inode,
+static void get_inode_version(struct inode * inode,
 			       struct ext2_group_desc *gdp,
 			       int mode)
 {
-	inode->u.ext2_i.i_version++;
+	get_random_bytes(&inode->u.ext2_i.i_version,
+			 sizeof(inode->u.ext2_i.i_version));
 	mark_inode_dirty(inode);
 
 	return;
@@ -494,10 +496,10 @@
 		inode->i_flags |= MS_SYNCHRONOUS;
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
-	inc_inode_version (inode, gdp, mode);
+	get_inode_version(inode, gdp, mode);
 
 	unlock_super (sb);
-	if(DQUOT_ALLOC_INODE(sb, inode)) {
+	if (DQUOT_ALLOC_INODE(sb, inode)) {
 		sb->dq_op->drop(inode);
 		inode->i_nlink = 0;
 		iput(inode);
diff -u -X exclude linux-2.2.1/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- linux-2.2.1/net/sunrpc/svcsock.c	Mon Feb 22 19:36:47 1999
+++ linux/net/sunrpc/svcsock.c	Mon Feb 22 19:43:48 1999
@@ -621,11 +621,11 @@
 		if (!(svsk->sk_reclen & 0x80000000)) {
 			/* FIXME: shutdown socket */
 			printk(KERN_NOTICE "RPC: bad TCP reclen %08lx",
-					(unsigned long) svsk->sk_reclen);
+			       (unsigned long) svsk->sk_reclen);
 			return -EIO;
 		}
 		svsk->sk_reclen &= 0x7fffffff;
-		dprintk("svc: TCP record, %ld bytes\n", svsk->sk_reclen);
+		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
 	}
 
 	/* Check whether enough data is available */
@@ -634,8 +634,8 @@
 		goto error;
 
 	if (len < svsk->sk_reclen) {
-		dprintk("svc: incomplete TCP record (%d of %ld)\n",
-				len, svsk->sk_reclen);
+		dprintk("svc: incomplete TCP record (%d of %d)\n",
+			len, svsk->sk_reclen);
 		svc_sock_received(svsk, ready);
 		len = -EAGAIN;	/* record not complete */
 	}
