diff -dpruN Linux-2.4.3/fs/exec.c linux/fs/exec.c
--- Linux-2.4.3/fs/exec.c	Thu Apr  5 00:20:29 2001
+++ linux/fs/exec.c	Sat Apr  7 12:45:01 2001
@@ -104,7 +104,9 @@ asmlinkage long sys_uselib(const char * 
 	struct file * file;
 	struct nameidata nd;
 	int error;
+	int retries = 1;
 
+retry_lookup:
 	error = user_path_walk(library, &nd);
 	if (error)
 		goto out;
@@ -119,8 +121,16 @@ asmlinkage long sys_uselib(const char * 
 
 	file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
 	error = PTR_ERR(file);
-	if (IS_ERR(file))
+	if (IS_ERR(file)) {
+		if (error == -ESTALE) {
+			if (retries) {
+				retries--;
+				goto retry_lookup;
+			}
+			error = -ENOENT;
+		}
 		goto out;
+	}
 
 	error = -ENOEXEC;
 	if(file->f_op && file->f_op->read) {
@@ -340,7 +350,9 @@ struct file *open_exec(const char *name)
 	struct inode *inode;
 	struct file *file;
 	int err = 0;
+	int retries = 1;
 
+retry_lookup:
 	if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
 		err = path_walk(name, &nd);
 	file = ERR_PTR(err);
@@ -358,9 +370,17 @@ struct file *open_exec(const char *name)
 						fput(file);
 						file = ERR_PTR(err);
 					}
-				}
 out:
-				return file;
+					return file;
+				}
+				if (PTR_ERR(file) == -ESTALE) {
+					if (retries) {
+						retries--;
+						goto retry_lookup;
+					}
+					file = ERR_PTR(-ENOENT);
+				}
+				goto out;
 			}
 		}
 		path_release(&nd);
diff -dpruN Linux-2.4.3/fs/nfs/dir.c linux/fs/nfs/dir.c
--- Linux-2.4.3/fs/nfs/dir.c	Thu Apr  5 00:20:29 2001
+++ linux/fs/nfs/dir.c	Fri Apr  6 19:17:06 2001
@@ -420,145 +420,6 @@ static int nfs_readdir(struct file *filp
 }
 
 /*
- * Whenever an NFS operation succeeds, we know that the dentry
- * is valid, so we update the revalidation timestamp.
- */
-static inline void nfs_renew_times(struct dentry * dentry)
-{
-	dentry->d_time = jiffies;
-}
-
-static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
-{
-	struct inode *inode = dentry->d_inode;
-	unsigned long timeout = NFS_ATTRTIMEO(inode);
-
-	/*
-	 * If it's the last lookup in a series, we use a stricter
-	 * cache consistency check by looking at the parent mtime.
-	 *
-	 * If it's been modified in the last hour, be really strict.
-	 * (This still means that we can avoid doing unnecessary
-	 * work on directories like /usr/share/bin etc which basically
-	 * never change).
-	 */
-	if (!(flags & LOOKUP_CONTINUE)) {
-		long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
-
-		if (diff < 15*60)
-			timeout = 0;
-	}
-	
-	return time_after(jiffies,dentry->d_time + timeout);
-}
-
-/*
- * We judge how long we want to trust negative
- * dentries by looking at the parent inode mtime.
- *
- * If mtime is close to present time, we revalidate
- * more often.
- */
-#define NFS_REVALIDATE_NEGATIVE (1 * HZ)
-static inline int nfs_neg_need_reval(struct dentry *dentry)
-{
-	struct inode *dir = dentry->d_parent->d_inode;
-	unsigned long timeout = NFS_ATTRTIMEO(dir);
-	long diff = CURRENT_TIME - dir->i_mtime;
-
-	if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
-		timeout = NFS_REVALIDATE_NEGATIVE;
-
-	return time_after(jiffies, dentry->d_time + timeout);
-}
-
-/*
- * This is called every time the dcache has a lookup hit,
- * and we should check whether we can really trust that
- * lookup.
- *
- * NOTE! The hit can be a negative hit too, don't assume
- * we have an inode!
- *
- * If the dentry is older than the revalidation interval, 
- * we do a new lookup and verify that the dentry is still
- * correct.
- */
-static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
-{
-	struct inode *dir;
-	struct inode *inode;
-	int error;
-	struct nfs_fh fhandle;
-	struct nfs_fattr fattr;
-
-	lock_kernel();
-	dir = dentry->d_parent->d_inode;
-	inode = dentry->d_inode;
-	/*
-	 * If we don't have an inode, let's look at the parent
-	 * directory mtime to get a hint about how often we
-	 * should validate things..
-	 */
-	if (!inode) {
-		if (nfs_neg_need_reval(dentry))
-			goto out_bad;
-		goto out_valid;
-	}
-
-	if (is_bad_inode(inode)) {
-		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name);
-		goto out_bad;
-	}
-
-	if (!nfs_dentry_force_reval(dentry, flags))
-		goto out_valid;
-
-	if (IS_ROOT(dentry)) {
-		__nfs_revalidate_inode(NFS_SERVER(inode), inode);
-		goto out_valid_renew;
-	}
-
-	/*
-	 * Do a new lookup and check the dentry attributes.
-	 */
-	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
-	if (error)
-		goto out_bad;
-
-	/* Inode number matches? */
-	if (!(fattr.valid & NFS_ATTR_FATTR) ||
-	    NFS_FSID(inode) != fattr.fsid ||
-	    NFS_FILEID(inode) != fattr.fileid)
-		goto out_bad;
-
-	/* Ok, remember that we successfully checked it.. */
-	nfs_refresh_inode(inode, &fattr);
-
-	if (nfs_inode_is_stale(inode, &fhandle, &fattr))
-		goto out_bad;
-
- out_valid_renew:
-	nfs_renew_times(dentry);
-out_valid:
-	unlock_kernel();
-	return 1;
-out_bad:
-	shrink_dcache_parent(dentry);
-	/* If we have submounts, don't unhash ! */
-	if (have_submounts(dentry))
-		goto out_valid;
-	d_drop(dentry);
-	/* Purge readdir caches. */
-	nfs_zap_caches(dir);
-	if (inode && S_ISDIR(inode->i_mode))
-		nfs_zap_caches(inode);
-	unlock_kernel();
-	return 0;
-}
-
-/*
  * This is called from dput() when d_count is going to 0.
  */
 static int nfs_dentry_delete(struct dentry *dentry)
@@ -590,7 +451,6 @@ static void nfs_dentry_iput(struct dentr
 }
 
 struct dentry_operations nfs_dentry_operations = {
-	d_revalidate:	nfs_lookup_revalidate,
 	d_delete:	nfs_dentry_delete,
 	d_iput:		nfs_dentry_iput,
 };
@@ -622,7 +482,6 @@ static struct dentry *nfs_lookup(struct 
 		if (inode) {
 	    no_entry:
 			d_add(dentry, inode);
-			nfs_renew_times(dentry);
 			error = 0;
 		}
 	}
@@ -642,7 +501,6 @@ static int nfs_instantiate(struct dentry
 	inode = nfs_fhget(dentry, fhandle, fattr);
 	if (inode) {
 		d_instantiate(dentry, inode);
-		nfs_renew_times(dentry);
 		error = 0;
 	}
 	return error;
@@ -816,7 +674,6 @@ dentry->d_parent->d_name.name, dentry->d
 	qsilly.len  = strlen(silly);
 	error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
 	if (!error) {
-		nfs_renew_times(dentry);
 		d_move(dentry, sdentry);
 		error = nfs_async_unlink(dentry);
  		/* If we return 0 we don't unlink */
@@ -897,9 +754,6 @@ static int nfs_unlink(struct inode *dir,
 	error = nfs_sillyrename(dir, dentry);
 	if (error && error != -EBUSY) {
 		error = nfs_safe_remove(dentry);
-		if (!error) {
-			nfs_renew_times(dentry);
-		}
 	}
 	return error;
 }
diff -dpruN Linux-2.4.3/fs/nfs/file.c linux/fs/nfs/file.c
--- Linux-2.4.3/fs/nfs/file.c	Thu Apr  5 00:19:51 2001
+++ linux/fs/nfs/file.c	Fri Apr  6 19:17:19 2001
@@ -91,14 +91,13 @@ static ssize_t
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
 	struct dentry * dentry = file->f_dentry;
-	struct inode * inode = dentry->d_inode;
 	ssize_t result;
 
 	dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long) *ppos);
 
-	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	result = nfs_revalidate(dentry);
 	if (!result)
 		result = generic_file_read(file, buf, count, ppos);
 	return result;
@@ -108,13 +107,12 @@ static int
 nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	int	status;
+	int status;
 
 	dfprintk(VFS, "nfs: mmap(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
-	status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	status = nfs_revalidate(dentry);
 	if (!status)
 		status = generic_file_mmap(file, vma);
 	return status;
@@ -224,7 +222,7 @@ nfs_file_write(struct file *file, const 
 	result = -EBUSY;
 	if (IS_SWAPFILE(inode))
 		goto out_swapfile;
-	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	result = nfs_revalidate(dentry);
 	if (result)
 		goto out;
 
diff -dpruN Linux-2.4.3/fs/nfs/inode.c linux/fs/nfs/inode.c
--- Linux-2.4.3/fs/nfs/inode.c	Thu Apr  5 00:20:29 2001
+++ linux/fs/nfs/inode.c	Sat Apr  7 15:37:55 2001
@@ -627,27 +627,6 @@ nfs_find_actor(struct inode *inode, unsi
 	return 1;
 }
 
-int
-nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
-{
-	/* Empty inodes are not stale */
-	if (!inode->i_mode)
-		return 0;
-
-	if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		return 1;
-
-	if (is_bad_inode(inode))
-		return 1;
-
-	/* Has the filehandle changed? If so is the old one stale? */
-	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
-	    __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
-		return 1;
-
-	return 0;
-}
-
 /*
  * This is our own version of iget that looks up inodes by file handle
  * instead of inode number.  We use this technique instead of using
@@ -775,35 +754,46 @@ nfs_wait_on_inode(struct inode *inode, i
 }
 
 /*
- * Externally visible revalidation function
+ * Soft revalidation -- if the attributes were checked recently,
+ * pretend they are up to date.  Everyone except nfs_open uses this.
  */
 int
 nfs_revalidate(struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	return nfs_revalidate_inode(NFS_SERVER(inode), inode);
+
+	if (time_before(jiffies, (NFS_READTIME(inode) + NFS_ATTRTIMEO(inode))))
+		return NFS_STALE(inode) ? -ESTALE : 0;
+
+	return __nfs_revalidate_inode(dentry);
 }
 
-/*
- * These are probably going to contain hooks for
- * allocating and releasing RPC credentials for
- * the file. I'll have to think about Tronds patch
- * a bit more..
- */
-int nfs_open(struct inode *inode, struct file *filp)
+int
+nfs_open(struct inode *inode, struct file *filp)
 {
+	int error;
 	struct rpc_auth *auth;
 	struct rpc_cred *cred;
 
-	lock_kernel();
-	auth = NFS_CLIENT(inode)->cl_auth;
-	cred = rpcauth_lookupcred(auth, 0);
-	filp->private_data = cred;
-	unlock_kernel();
-	return 0;
+	/*
+	 * Close-to-open cache consistency requires that open()
+	 * check the server version of this object's attributes.
+	 * See Callaghan's "NFS Illustrated" ss. 7.3.2 and 8.14.2
+	 */
+	error = __nfs_revalidate_inode(filp->f_dentry);
+	if (!error) {
+		lock_kernel();
+		auth = NFS_CLIENT(inode)->cl_auth;
+		cred = rpcauth_lookupcred(auth, 0);
+		filp->private_data = cred;
+		unlock_kernel();
+	}
+
+	return error;
 }
 
-int nfs_release(struct inode *inode, struct file *filp)
+int
+nfs_release(struct inode *inode, struct file *filp)
 {
 	struct rpc_auth *auth;
 	struct rpc_cred *cred;
@@ -817,31 +807,54 @@ int nfs_release(struct inode *inode, str
 	return 0;
 }
 
+static void
+nfs_invalidate_dentry(struct dentry *dentry)
+{
+	struct inode * inode = dentry->d_inode;
+
+	/* Safety first */
+	if (!inode)
+		return;
+
+	dfprintk(PAGECACHE, "NFS: invalidating (%x/%Ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode));
+
+        shrink_dcache_parent(dentry);
+
+        /* If we have submounts, don't unhash ! */
+        if (have_submounts(dentry))
+		return;
+
+        d_drop(dentry);
+
+        /* Purge readdir caches. */
+        nfs_zap_caches(dentry->d_parent->d_inode);
+        if (inode && S_ISDIR(inode->i_mode))
+               	nfs_zap_caches(inode);
+}
+
 /*
  * This function is called whenever some part of NFS notices that
  * the cached attributes have to be refreshed.
  */
 int
-__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+__nfs_revalidate_inode(struct dentry * dentry)
 {
-	int		 status = 0;
+	int status = -ESTALE;
+	struct inode *inode = dentry->d_inode;
 	struct nfs_fattr fattr;
 
 	dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
 		inode->i_dev, (long long)NFS_FILEID(inode));
 
 	lock_kernel();
-	if (!inode || is_bad_inode(inode) || NFS_STALE(inode)) {
-		unlock_kernel();
-		return -ESTALE;
-	}
+	if (is_bad_inode(inode) || NFS_STALE(inode))
+		goto out_nowait;
 
 	while (NFS_REVALIDATING(inode)) {
 		status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
-		if (status < 0) {
-			unlock_kernel();
-			return status;
-		}
+		if (status < 0)
+			goto out_nowait;
 		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
 			status = NFS_STALE(inode) ? -ESTALE : 0;
 			goto out_nowait;
@@ -851,7 +864,8 @@ __nfs_revalidate_inode(struct nfs_server
 
 	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
+		dfprintk(PAGECACHE, __FUNCTION__
+			": (%x/%Ld) getattr failed, error=%d\n",
 			 inode->i_dev, (long long)NFS_FILEID(inode), status);
 		if (status == -ESTALE) {
 			NFS_FLAGS(inode) |= NFS_INO_STALE;
@@ -860,18 +874,33 @@ __nfs_revalidate_inode(struct nfs_server
 		goto out;
 	}
 
+	/*
+	 * When we detect a directory change on the server,
+	 * we throw away cached lookup results.
+	 */
+	if (S_ISDIR(inode->i_mode))
+		if ((NFS_CACHE_ISIZE(inode) != fattr.size) ||
+		    (NFS_CACHE_MTIME(inode) != fattr.mtime))
+			shrink_dcache_parent(dentry);
+
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
+		dfprintk(PAGECACHE, __FUNCTION__
+			": (%x/%Ld) refresh failed, error=%d\n",
 			 inode->i_dev, (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
+
 	dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
 		inode->i_dev, (long long)NFS_FILEID(inode));
 out:
 	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
 	wake_up(&inode->i_wait);
- out_nowait:
+
+out_nowait:
+	if (status == -ESTALE)
+		nfs_invalidate_dentry(dentry);
+
 	unlock_kernel();
 	return status;
 }
diff -dpruN Linux-2.4.3/fs/open.c linux/fs/open.c
--- Linux-2.4.3/fs/open.c	Thu Apr  5 00:19:52 2001
+++ linux/fs/open.c	Sat Apr  7 12:38:00 2001
@@ -614,8 +614,10 @@ asmlinkage long sys_fchown(unsigned int 
  */
 struct file *filp_open(const char * filename, int flags, int mode)
 {
+	unsigned retries = 1;
 	int namei_flags, error;
 	struct nameidata nd;
+	struct file * file;
 
 	namei_flags = flags;
 	if ((namei_flags+1) & O_ACCMODE)
@@ -623,11 +625,21 @@ struct file *filp_open(const char * file
 	if (namei_flags & O_TRUNC)
 		namei_flags |= 2;
 
+retry_lookup:
 	error = open_namei(filename, namei_flags, mode, &nd);
-	if (!error)
-		return dentry_open(nd.dentry, nd.mnt, flags);
+	if (error)
+		return ERR_PTR(error);
 
-	return ERR_PTR(error);
+	file = dentry_open(nd.dentry, nd.mnt, flags);
+	if (PTR_ERR(file) != -ESTALE)
+		return file;
+
+	if (retries) {
+		retries--;
+		goto retry_lookup;
+	}
+
+	return ERR_PTR(-ENOENT);
 }
 
 struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
diff -dpruN Linux-2.4.3/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- Linux-2.4.3/include/linux/nfs_fs.h	Thu Jan  4 17:50:54 2001
+++ linux/include/linux/nfs_fs.h	Fri Apr  6 16:38:56 2001
@@ -148,7 +148,7 @@ extern int nfs_revalidate(struct dentry 
 extern int nfs_permission(struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
 extern int nfs_release(struct inode *, struct file *);
-extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
+extern int __nfs_revalidate_inode(struct dentry *);
 extern int nfs_notify_change(struct dentry *, struct iattr *);
 
 /*
@@ -266,14 +266,6 @@ extern int  nfs3_mount(struct sockaddr_i
 /*
  * inline functions
  */
-static inline int
-nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
-{
-	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-		return NFS_STALE(inode) ? -ESTALE : 0;
-	return __nfs_revalidate_inode(server, inode);
-}
-
 static inline loff_t
 nfs_size_to_loff_t(__u64 size)
 {
diff -dpruN Linux-2.4.3/include/linux/sunrpc/debug.h linux/include/linux/sunrpc/debug.h
--- Linux-2.4.3/include/linux/sunrpc/debug.h	Thu Jan  4 17:50:47 2001
+++ linux/include/linux/sunrpc/debug.h	Fri Apr  6 11:37:47 2001
@@ -49,7 +49,7 @@ extern unsigned int		nfsd_debug;
 extern unsigned int		nlm_debug;
 #endif
 
-#define dprintk(args...)	dfprintk(FACILITY, ## args)
+#define dprintk(args...)	/* */
 
 #undef ifdebug
 #ifdef RPC_DEBUG			
