diff -urN 2.4.19pre6aa1/fs/nfs/dir.c nfs/fs/nfs/dir.c --- 2.4.19pre6aa1/fs/nfs/dir.c Fri Apr 5 20:19:43 2002 +++ nfs/fs/nfs/dir.c Fri Apr 5 20:22:01 2002 @@ -423,21 +423,6 @@ } /* - * A check for whether or not the parent directory has changed. - * In the case it has, we assume that the dentries are untrustworthy - * and may need to be looked up again. - */ -static inline -int nfs_check_verifier(struct inode *dir, struct dentry *dentry) -{ - if (IS_ROOT(dentry)) - return 1; - if (nfs_revalidate_inode(NFS_SERVER(dir), dir)) - return 0; - return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir)); -} - -/* * Whenever an NFS operation succeeds, we know that the dentry * is valid, so we update the revalidation timestamp. */ @@ -446,31 +431,48 @@ dentry->d_time = jiffies; } -static inline -int nfs_lookup_verify_inode(struct inode *inode, int flags) +static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags) { - struct nfs_server *server = NFS_SERVER(inode); + struct inode *inode = dentry->d_inode; + unsigned long timeout = NFS_ATTRTIMEO(inode); + /* - * If we're interested in close-to-open cache consistency, - * then we revalidate the inode upon lookup. + * 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 (!(server->flags & NFS_MOUNT_NOCTO) && !(flags & LOOKUP_CONTINUE)) - NFS_CACHEINV(inode); - return nfs_revalidate_inode(server, inode); + 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 parent mtime has changed, we revalidate, else we wait for a - * period corresponding to the parent's attribute cache timeout value. + * If mtime is close to present time, we revalidate + * more often. */ -static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry) +#define NFS_REVALIDATE_NEGATIVE (1 * HZ) +static inline int nfs_neg_need_reval(struct dentry *dentry) { - if (!nfs_check_verifier(dir, dentry)) - return 1; - return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir)); + 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); } /* @@ -481,8 +483,9 @@ * NOTE! The hit can be a negative hit too, don't assume * we have an inode! * - * If the parent directory is seen to have changed, we throw out the - * cached dentry and do a new lookup. + * 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) { @@ -495,9 +498,13 @@ 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(dir, dentry)) + if (nfs_neg_need_reval(dentry)) goto out_bad; goto out_valid; } @@ -508,39 +515,48 @@ goto out_bad; } - /* Force a full look up iff the parent directory has changed */ - if (nfs_check_verifier(dir, dentry)) { - if (nfs_lookup_verify_inode(inode, flags)) - goto out_bad; + if (!nfs_dentry_force_reval(dentry, flags)) goto out_valid; - } - if (NFS_STALE(inode)) - goto out_bad; + 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; - if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) + + /* Inode number matches? */ + if (!(fattr.valid & NFS_ATTR_FATTR) || + NFS_FSID(inode) != fattr.fsid || + NFS_FILEID(inode) != fattr.fileid) goto out_bad; - if ((error = nfs_refresh_inode(inode, &fattr)) != 0) + + /* 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: +out_valid: unlock_kernel(); return 1; - out_bad: - NFS_CACHEINV(dir); - if (inode && S_ISDIR(inode->i_mode)) { - /* Purge readdir caches. */ - nfs_zap_caches(inode); - /* If we have submounts, don't unhash ! */ - if (have_submounts(dentry)) - goto out_valid; - shrink_dcache_parent(dentry); - } +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; } @@ -573,8 +589,6 @@ nfs_complete_unlink(dentry); unlock_kernel(); } - if (is_bad_inode(inode)) - force_delete(inode); iput(inode); } @@ -611,9 +625,9 @@ if (inode) { no_entry: d_add(dentry, inode); + nfs_renew_times(dentry); error = 0; } - nfs_renew_times(dentry); } out: return ERR_PTR(error); diff -urN 2.4.19pre6aa1/fs/nfs/inode.c nfs/fs/nfs/inode.c --- 2.4.19pre6aa1/fs/nfs/inode.c Fri Apr 5 20:19:43 2002 +++ nfs/fs/nfs/inode.c Fri Apr 5 20:22:01 2002 @@ -660,6 +660,7 @@ */ if (inode->i_mode == 0) { NFS_FILEID(inode) = fattr->fileid; + NFS_FSID(inode) = fattr->fsid; inode->i_mode = fattr->mode; /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. @@ -698,18 +699,39 @@ struct nfs_fh *fh = desc->fh; struct nfs_fattr *fattr = desc->fattr; + if (NFS_FSID(inode) != fattr->fsid) + return 0; if (NFS_FILEID(inode) != fattr->fileid) return 0; if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0) return 0; - if (is_bad_inode(inode)) - return 0; /* Force an attribute cache update if inode->i_count == 0 */ if (!atomic_read(&inode->i_count)) NFS_CACHEINV(inode); 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) || NFS_STALE(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,7 +797,7 @@ /* * Make sure the inode is up-to-date. */ - error = nfs_revalidate_inode(NFS_SERVER(inode),inode); + error = nfs_revalidate(dentry); if (error) { #ifdef NFS_PARANOIA printk("nfs_notify_change: revalidate failed, error=%d\n", error); @@ -1021,11 +1043,12 @@ inode->i_dev, inode->i_ino, atomic_read(&inode->i_count), fattr->valid); - if (NFS_FILEID(inode) != fattr->fileid) { + if (NFS_FSID(inode) != fattr->fsid || + NFS_FILEID(inode) != fattr->fileid) { printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n" - "expected (0x%x/0x%Lx), got (0x%x/0x%Lx)\n", - inode->i_dev, (long long)NFS_FILEID(inode), - inode->i_dev, (long long)fattr->fileid); + "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n", + (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode), + (long long)fattr->fsid, (long long)fattr->fileid); goto out_err; } @@ -1096,11 +1119,8 @@ inode->i_atime = new_atime; - if (NFS_CACHE_MTIME(inode) != new_mtime) { - NFS_MTIME_UPDATE(inode) = jiffies; - NFS_CACHE_MTIME(inode) = new_mtime; - inode->i_mtime = nfs_time_to_secs(new_mtime); - } + NFS_CACHE_MTIME(inode) = new_mtime; + inode->i_mtime = nfs_time_to_secs(new_mtime); NFS_CACHE_ISIZE(inode) = new_size; inode->i_size = new_isize; diff -urN 2.4.19pre6aa1/fs/nfs/nfs3proc.c nfs/fs/nfs/nfs3proc.c --- 2.4.19pre6aa1/fs/nfs/nfs3proc.c Fri Apr 5 20:19:43 2002 +++ nfs/fs/nfs/nfs3proc.c Fri Apr 5 20:22:01 2002 @@ -111,8 +111,7 @@ status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply lookup: %d\n", status); - if (status >= 0) - status = nfs_refresh_inode(dir, &dir_attr); + nfs_refresh_inode(dir, &dir_attr); return status; } diff -urN 2.4.19pre6aa1/include/linux/nfs_fs.h nfs/include/linux/nfs_fs.h --- 2.4.19pre6aa1/include/linux/nfs_fs.h Fri Apr 5 20:19:44 2002 +++ nfs/include/linux/nfs_fs.h Fri Apr 5 20:22:01 2002 @@ -78,7 +78,6 @@ #define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode))) #define NFS_COOKIEVERF(inode) ((inode)->u.nfs_i.cookieverf) #define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies) -#define NFS_MTIME_UPDATE(inode) ((inode)->u.nfs_i.cache_mtime_jiffies) #define NFS_CACHE_CTIME(inode) ((inode)->u.nfs_i.read_cache_ctime) #define NFS_CACHE_MTIME(inode) ((inode)->u.nfs_i.read_cache_mtime) #define NFS_CACHE_ISIZE(inode) ((inode)->u.nfs_i.read_cache_isize) @@ -98,6 +97,7 @@ #define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE) #define NFS_FILEID(inode) ((inode)->u.nfs_i.fileid) +#define NFS_FSID(inode) ((inode)->u.nfs_i.fsid) /* Inode Flags */ #define NFS_USE_READDIRPLUS(inode) ((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0) @@ -152,7 +152,6 @@ 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_check_stale(struct inode *); extern int nfs_notify_change(struct dentry *, struct iattr *); /* diff -urN 2.4.19pre6aa1/include/linux/nfs_fs_i.h nfs/include/linux/nfs_fs_i.h --- 2.4.19pre6aa1/include/linux/nfs_fs_i.h Fri Apr 5 20:00:43 2002 +++ nfs/include/linux/nfs_fs_i.h Fri Apr 5 20:22:01 2002 @@ -12,6 +12,7 @@ /* * The 64bit 'inode number' */ + __u64 fsid; __u64 fileid; /* @@ -49,12 +50,6 @@ unsigned long attrtimeo_timestamp; /* - * Timestamp that dates the change made to read_cache_mtime. - * This is of use for dentry revalidation - */ - unsigned long cache_mtime_jiffies; - - /* * This is the cookie verifier used for NFSv3 readdir * operations */ @@ -72,6 +67,11 @@ ndirty, ncommit, npages; + + /* Flush daemon info */ + struct inode *hash_next, + *hash_prev; + unsigned long nextscan; /* Credentials for shared mmap */ struct rpc_cred *mm_cred;