diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 538ca18efe0d..08b499504f63 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -1015,7 +1015,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) struct dentry *parent; struct inode *inode; struct key *key; - void *dir_version; + long dir_version, de_version; int ret; if (flags & LOOKUP_RCU) @@ -1059,9 +1059,19 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) goto out_bad_parent; } - dir_version = (void *) (unsigned long) dir->status.data_version; - if (dentry->d_fsdata == dir_version) - goto out_valid; /* the dir contents are unchanged */ + /* We only need to invalidate a dentry if the server's copy changed + * behind our back. If we made the change, it's no problem. Note that + * on a 32-bit system, we only have 32 bits in the dentry to store the + * version. + */ + dir_version = (long)dir->status.data_version; + de_version = (long)dentry->d_fsdata; + if (de_version == dir_version) + goto out_valid; + + dir_version = (long)dir->invalid_before; + if (de_version - dir_version >= 0) + goto out_valid; _debug("dir modified"); afs_stat_v(dir, n_reval); @@ -1120,7 +1130,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) } out_valid: - dentry->d_fsdata = dir_version; + dentry->d_fsdata = (void *)dir_version; dput(parent); key_put(key); _leave(" = 1 [valid]"); diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index ff87fc6bb27f..f7570d229dcc 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -100,6 +100,7 @@ void afs_update_inode_from_status(struct afs_vnode *vnode, (unsigned long long) status->data_version, vnode->fid.vid, vnode->fid.vnode, (unsigned long long) *expected_version); + vnode->invalid_before = status->data_version; set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); } diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 2e32d475ec11..07f450513f3e 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -83,6 +83,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key) inode->i_blocks = 0; inode->i_mapping->a_ops = &afs_fs_aops; + vnode->invalid_before = vnode->status.data_version; read_sequnlock_excl(&vnode->cb_lock); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index ac3076c2a8e8..adf9b17d328c 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -479,6 +479,7 @@ struct afs_vnode { struct afs_volume *volume; /* volume on which vnode resides */ struct afs_fid fid; /* the file identifier for this inode */ struct afs_file_status status; /* AFS status info for this file */ + afs_dataversion_t invalid_before; /* Child dentries are invalid before this */ #ifdef CONFIG_AFS_FSCACHE struct fscache_cookie *cache; /* caching cookie */ #endif