patch-2.1.120 linux/fs/nfs/dir.c

Next file: linux/fs/nfs/write.c
Previous file: linux/fs/lockd/svc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.119/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
@@ -29,11 +29,6 @@
 
 #include <asm/segment.h>	/* for fs functions */
 
-#define NFS_MAX_AGE 10*HZ	/* max age for dentry validation */
-
-/* needed by smbfs as well ... move to dcache? */
-extern void nfs_renew_times(struct dentry *);
-
 #define NFS_PARANOIA 1
 /* #define NFS_DEBUG_VERBOSE 1 */
 
@@ -376,6 +371,7 @@
 	nfs_invalidate_dircache_sb(NULL);
 }
 
+#define NFS_REVALIDATE_INTERVAL (5*HZ)
 /*
  * This is called every time the dcache has a lookup hit,
  * and we should check whether we can really trust that
@@ -384,36 +380,69 @@
  * NOTE! The hit can be a negative hit too, don't assume
  * we have an inode!
  *
- * The decision to drop the dentry should probably be
- * smarter than this. Right now we believe in directories
- * for 10 seconds, and in normal files for five..
+ * 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)
 {
+	struct dentry * parent = dentry->d_parent;
+	struct inode * inode = dentry->d_inode;
 	unsigned long time = jiffies - dentry->d_time;
-	unsigned long max = 5*HZ;
+	int error;
+	struct nfs_fh fhandle;
+	struct nfs_fattr fattr;
 
-	if (dentry->d_inode) {
-		if (is_bad_inode(dentry->d_inode)) {
+	if (inode && is_bad_inode(inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_lookup_validate: %s/%s has dud inode\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+parent->d_name.name, dentry->d_name.name);
 #endif
-			goto bad;
-		}
-		if (S_ISDIR(dentry->d_inode->i_mode))
-			max = NFS_MAX_AGE;
+		goto out_bad;
 	}
 
-	return (time < max) || IS_ROOT(dentry);
-bad:
+	if (time < NFS_REVALIDATE_INTERVAL)
+		goto out_valid;
+	/*
+	 * Don't bother looking up a negative dentry ...
+	 */
+	if (!inode)
+		goto out_bad;
+
+	if (IS_ROOT(dentry))
+		goto out_valid;
+	/*
+	 * Do a new lookup and check the dentry attributes.
+	 */
+	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), 
+				dentry->d_name.name, &fhandle, &fattr);
+	if (error) {
+printk("nfs_lookup_revalidate: error=%d\n", error);
+		goto out_bad;
+	}
+
+	/* Inode number matches? */
+	if (fattr.fileid != inode->i_ino) {
+printk("nfs_lookup_revalidate: %s/%s inode mismatch, old=%ld, new=%u\n",
+parent->d_name.name, dentry->d_name.name, inode->i_ino, fattr.fileid);
+		goto out_bad;
+	}
+	/* Filehandle matches? */
+	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
+printk("nfs_lookup_revalidate: %s/%s fh changed\n",
+parent->d_name.name, dentry->d_name.name);
+		goto out_bad;
+	}
+
+out_valid:
+	return 1;
+out_bad:
 	return 0;
 }
 
 /*
  * This is called from dput() when d_count is going to 0.
- * We use it to clean up silly-renamed files, and to check
- * for dentries that have already expired.
+ * We use it to clean up silly-renamed files.
  */
 static void nfs_dentry_delete(struct dentry *dentry)
 {
@@ -433,14 +462,6 @@
 				dentry->d_parent->d_name.name,
 				dentry->d_name.name, error);
 	}
-	/*
-	 * Check whether to expire the dentry ...
-	 */
-	else {
-		unsigned long age = jiffies - dentry->d_time;
-		if (age > NFS_MAX_AGE)
-			d_drop(dentry);
-	}
 
 #ifdef NFS_PARANOIA
 	/*
@@ -523,17 +544,12 @@
 #endif
 
 /*
- * Whenever a lookup succeeds, we know the parent directories
- * are all valid, so we want to update the dentry timestamps.
+ * Whenever an NFS operation succeeds, we know that the dentry
+ * is valid, so we update the revalidation timestamp.
  */
-void nfs_renew_times(struct dentry * dentry)
+static inline void nfs_renew_times(struct dentry * dentry)
 {
-	for (;;) {
-		dentry->d_time = jiffies;
-		if (dentry == dentry->d_parent)
-			break;
-		dentry = dentry->d_parent;
-	}
+	dentry->d_time = jiffies;
 }
 
 static int nfs_lookup(struct inode *dir, struct dentry * dentry)
@@ -546,11 +562,6 @@
 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_lookup: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
-
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
 		goto out;
@@ -635,12 +646,7 @@
 	struct nfs_fh fhandle;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-				dir->i_dev, dir->i_ino, dentry->d_name.name);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_create: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
@@ -675,12 +681,7 @@
 	struct nfs_fh fhandle;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-				dir->i_dev, dir->i_ino, dentry->d_name.name);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_mknod: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
 		return -ENAMETOOLONG;
@@ -712,12 +713,7 @@
 	struct nfs_fh fhandle;
 
 	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-				dir->i_dev, dir->i_ino, dentry->d_name.name);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_mkdir: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
@@ -754,12 +750,7 @@
 	int error, rehash = 0;
 
 	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-				dir->i_dev, dir->i_ino, dentry->d_name.name);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_rmdir: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
@@ -1010,12 +1001,7 @@
 	int error;
 
 	dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
-				dir->i_dev, dir->i_ino, dentry->d_name.name);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_unlink: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
@@ -1039,12 +1025,7 @@
 	int error;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-			dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_symlink: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)
@@ -1095,11 +1076,6 @@
 	dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
 		old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
 		dentry->d_parent->d_name.name, dentry->d_name.name);
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("nfs_link: dir is NULL or not a directory\n");
-		return -ENOENT;
-	}
 
 	error = -ENAMETOOLONG;
 	if (dentry->d_name.len > NFS_MAXNAMLEN)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov