From d39ab9de3b80da5835049b1c3b49da4e84e01c07 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Fri, 24 Sep 2010 18:50:01 -0400 Subject: NFS: re-add readdir plus This patch adds readdir plus support to the cache array. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'fs/nfs/dir.c') diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 33b0ce7a97b..fd30f185ec0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -370,6 +370,71 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, __be32 * return 0; } +static +int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) +{ + struct nfs_inode *node; + if (dentry->d_inode == NULL) + goto different; + node = NFS_I(dentry->d_inode); + if (node->fh.size != entry->fh->size) + goto different; + if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0) + goto different; + return 1; +different: + return 0; +} + +static +void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) +{ + struct qstr filename; + struct dentry *dentry = NULL; + struct dentry *alias = NULL; + struct inode *dir = parent->d_inode; + struct inode *inode; + + nfs_readdir_make_qstr(&filename, entry->name, entry->len); + if (filename.len == 1 && filename.name[0] == '.') + dentry = dget(parent); + else if (filename.len == 2 && filename.name[0] == '.' + && filename.name[1] == '.') + dentry = dget_parent(parent); + else + dentry = d_lookup(parent, &filename); + + if (dentry != NULL) { + if (nfs_same_file(dentry, entry)) { + nfs_refresh_inode(dentry->d_inode, entry->fattr); + goto out; + } else { + d_drop(dentry); + dput(dentry); + } + } + + dentry = d_alloc(parent, &filename); + dentry->d_op = NFS_PROTO(dir)->dentry_ops; + inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); + if (IS_ERR(inode)) + goto out; + + alias = d_materialise_unique(dentry, inode); + if (IS_ERR(alias)) + goto out; + else if (alias) { + nfs_set_verifier(alias, nfs_save_change_attribute(dir)); + dput(alias); + } else + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + +out: + dput(dentry); + kfree(filename.name); + return; +} + /* Perform conversion from xdr to cache array */ static void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, @@ -379,6 +444,8 @@ void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *e while (xdr_decode(desc, entry, &ptr) == 0) { if (nfs_readdir_add_to_array(entry, page) == -1) break; + if (desc->plus == 1) + nfs_prime_dcache(desc->file->f_path.dentry, entry); } kunmap(xdr_page); } -- cgit v1.2.3