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 00:46:41 1999
@@ -33,6 +33,7 @@
 	__u32		fb_dev;		/* our device */
 	__u32		fb_xdev;
 	__u32		fb_xino;
+	__u32		fb_version;
 };
 
 #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_version		fh_base.fb_version
 
 #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)
@@ -176,34 +181,6 @@
 		up(&inode->i_sem);
 	}
 }
-
-/*
- * Release an inode
- */
-#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
 
 #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 00:46:41 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	Mon Feb 22 00:47:34 1999
@@ -20,6 +20,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 +50,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 +71,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;
 
@@ -79,30 +82,36 @@
 		fp = list_entry(tmp, struct nfsd_fixup, lru);
 		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;
+printk("add_to_rename_cache: found %d, %d\n", dirino, new_dirino);
+		fp->new_dirino = new_dirino;
 		return;
 	}
 
@@ -113,16 +122,20 @@
 	 */
 	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;
+printk("add_to_rename_cache: adding %d, %d\n", dirino, new_dirino);
+		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);
@@ -210,9 +223,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,7 +312,7 @@
 	int result = 0;
 
 	buf->sequence++;
-#ifdef NFSD_DEBUG_VERBOSE
+#ifdef NFSD_DEBUG_VERY_VERBOSE
 printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
 #endif
 	if (buf->sequence == 2) {
@@ -309,7 +322,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 +532,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=%ld\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 +588,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 +604,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 +762,18 @@
 	return dentry;
 }
 
+static u32
+get_version(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 +781,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 +820,7 @@
 		return dentry;
 	}
 out:
+#endif
 	return NULL;
 }
 
@@ -841,13 +869,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 +882,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 +914,11 @@
 static struct dentry *
 find_fh_dentry(struct knfs_fh *fh)
 {
+	struct super_block *sb;
 	struct dentry *dentry, *parent;
+	struct inode * inode;
 	int looked_up = 0, retry = 0;
+	ino_t dirino;
 
 	/*
 	 * Stage 1: Look for the dentry in the short-term fhcache.
@@ -898,46 +928,70 @@
 		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("No SuperBlock for device.");
+		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) {
+		struct list_head *lst;
+		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("gam3: Found a useless inode\n");
+			    	continue;
+			}
+
+			if (dentry->d_parent->d_inode->i_ino
+			    == dirino) {
 
-		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);
+if (retry) {
+printk("gam3: Found renamed %s/%s filehandle dirino = %d, %ld\n",
+       dentry->d_parent->d_name.name,
+       dentry->d_name.name,
+       dentry->d_parent->d_inode->i_ino,
+       dirino);
+} else {
+printk("gam3: Found %s/%s filehandle dirino = %d, %ld\n",
+       dentry->d_parent->d_name.name,
+       dentry->d_name.name,
+       dentry->d_parent->d_inode->i_ino,
+       dirino);
+}
 #endif
-				if (!retry)
-					nfsdstats.fh_valid++;
-				else {
-					nfsdstats.fh_fixup++;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: retried validation successful\n");
+#if 0
+				iput(inode);
 #endif
-				}
+				dget(dentry);
 				goto out;
 			}
 		}
+		iput(inode);
+	} else {
+		printk("gam3: No inode found.\n");
 	}
-
+printk("gam3: dirino not found %d\n", dirino);
 	/*
-	 * 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 if a rename
 	 */
-	if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) {
+	if (!retry && (dirino = nfsd_cached_lookup(fh))) {
+printk("gam3: retry with %d\n", dirino);
 		retry = 1;
 		goto recheck;
 	}
@@ -983,30 +1037,47 @@
 	}
 
 	/*
-	 * Stage 5: Search the whole volume.
+	 * Stage 5: Search the whole volume, SURE.
 	 */
 #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);
+	}
 }
 
 /*
@@ -1024,8 +1095,10 @@
 	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/%ld file (%s/%ld dir %ld)\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 +1107,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 +1130,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 +1158,12 @@
 check_type:
 	dentry = fhp->fh_dentry;
 	inode = dentry->d_inode;
+	error = nfserr_stale;
+	if (get_version(inode) != fh->fh_version) {
+		dprintk("fh_verify: Bad version %u %u %u\n",
+			inode->i_ino, get_version(inode), fh->fh_version);
+ 		goto out;
+	}
 	exp = fhp->fh_export;
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
@@ -1106,13 +1190,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 +1252,14 @@
 	}
 	fh_init(fhp);
 
+#ifdef USE_COOKIE
 	fhp->fh_handle.fh_dcookie = dentry;
+#else
+	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+#endif
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
+		fhp->fh_handle.fh_version = get_version(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 +1291,7 @@
 	if (!inode)
 		goto out_negative;
 	fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
+	fhp->fh_handle.fh_version = get_version(inode);
 out:
 	return;
 
@@ -1317,7 +1407,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/nfsproc.c linux/fs/nfsd/nfsproc.c
--- linux-2.2.1/fs/nfsd/nfsproc.c	Wed Jul 22 14:37:36 1998
+++ linux/fs/nfsd/nfsproc.c	Mon Feb 22 00:46:41 1999
@@ -515,7 +515,7 @@
   PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT),
   PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
   PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLSTAT),
+  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF),
   PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE),
 };
 
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 00:46:41 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	Tue Feb  2 09:53:31 1999
+++ linux/fs/nfsd/vfs.c	Mon Feb 22 00:46:41 1999
@@ -21,7 +21,7 @@
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/ext2_fs.h>
+/* #include <linux/ext2_fs.h> */
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -658,10 +658,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 +666,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 +700,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;
 		}
@@ -734,7 +738,7 @@
 	 * directories via NFS.
 	 */
 	err = 0;
-	if ((iap->ia_valid &= (ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
 		err = nfsd_setattr(rqstp, resfhp, iap);
 out:
 	return err;
@@ -899,6 +903,7 @@
 	/* Compose the fh so the dentry will be freed ... */
 out_compose:
 	fh_compose(resfhp, fhp->fh_export, dnew);
+
 out:
 	return err;
 
@@ -1024,6 +1029,9 @@
 		up(s2);
 }
 
+/* FIXME: I belong in a header */
+void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino);
+
 /*
  * Rename a file
  * N.B. After this call _both_ ffhp and tfhp need an fh_put
@@ -1091,6 +1099,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 +1149,6 @@
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
-
 	if (!rdentry->d_inode) {
 		dput(rdentry);
 		err = nfserr_noent;
@@ -1151,7 +1167,7 @@
 		fh_unlock(fhp);
 
 		dput(rdentry);
-
+		expire_by_dentry(rdentry);
 	} else {
 		/* It's RMDIR */
 		/* See comments in fs/namei.c:do_rmdir */
@@ -1179,6 +1195,7 @@
 		goto out_nfserr;
 	if (EX_ISSYNC(fhp->fh_export))
 		write_inode_now(dirp);
+
 out:
 	return err;
 
@@ -1330,7 +1347,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 00:46:41 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	Thu Nov 12 08:33:29 1998
+++ linux/net/sunrpc/svcsock.c	Mon Feb 22 00:46:41 1999
@@ -620,11 +620,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 */
@@ -633,8 +633,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 */
 	}
