lkml.org 
[lkml]   [1998]   [Sep]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectpatch for 2.1.119 NFS cacheing
I'd like to get some of the loose ends with NFS client cleaned up in the
next week or two, and as a first step have made some changes to improve
file (page) cacheing.

The changes are quite simple -- when revalidating a dentry, do a lookup
on the server if the dentry is older than the revalidation age, and keep
the current dentry if the fh and inode number match the lookup. This
allows the inode and page cache to be retained if the dentry is still
valid.

(Contrary to contrary impressions, there's nothing "broken" with NFS
cacheing, it's just that dentries were given a very short lifetime.)

The nfs_renew_times routine has been made much more conservative, so
that it now updates only the dentry's timestamp after a successful
operation, rather than all of the parent dentries. This should still
help avoid some extra lookups though.

The patch also removes some unnecessary tests for NULL or non-directory
dir arguments, as the VFS guarantees that this argument will be valid.

I've tested the patch here extensively for at least ten minutes :-), so
maybe some others should test as well.

Regards,
Bill--- linux-2.1.119/fs/nfs/dir.c.old Tue Sep 1 21:40:19 1998
+++ linux-2.1.119/fs/nfs/dir.c Fri Sep 4 11:00:28 1998
@@ -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 +407,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 +416,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 +498,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 +580,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 +598,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 +682,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 +717,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 +749,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 +786,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 +1037,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 +1061,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 +1112,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)
\
 
 \ /
  Last update: 2005-03-22 13:44    [W:0.044 / U:1.168 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site