aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-02-07 17:02:08 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-02-11 14:01:20 -0500
commit311324ad1713666a6e803aecf0d4e1a136a5b34a (patch)
tree524ee4e8b5049a48ab9d3824eada3c5099de4dd2 /fs/nfs
parent2ea24497a1b30dd03dd42b873fa5097913587f4d (diff)
NFS: Be more aggressive in using readdirplus for 'ls -l' situations
Try to detect 'ls -l' by having nfs_getattr() look at whether or not there is an opendir() file descriptor for the parent directory. If so, then assume that we want to force use of readdirplus in order to avoid the multiple GETATTR calls over the wire. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c42
-rw-r--r--fs/nfs/inode.c34
-rw-r--r--fs/nfs/internal.h1
3 files changed, 66 insertions, 11 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index be38b573495a..c8e48c26418b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = {
69 69
70static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) 70static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
71{ 71{
72 struct nfs_inode *nfsi = NFS_I(dir);
72 struct nfs_open_dir_context *ctx; 73 struct nfs_open_dir_context *ctx;
73 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 74 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
74 if (ctx != NULL) { 75 if (ctx != NULL) {
75 ctx->duped = 0; 76 ctx->duped = 0;
76 ctx->attr_gencount = NFS_I(dir)->attr_gencount; 77 ctx->attr_gencount = nfsi->attr_gencount;
77 ctx->dir_cookie = 0; 78 ctx->dir_cookie = 0;
78 ctx->dup_cookie = 0; 79 ctx->dup_cookie = 0;
79 ctx->cred = get_rpccred(cred); 80 ctx->cred = get_rpccred(cred);
81 spin_lock(&dir->i_lock);
82 list_add(&ctx->list, &nfsi->open_files);
83 spin_unlock(&dir->i_lock);
80 return ctx; 84 return ctx;
81 } 85 }
82 return ERR_PTR(-ENOMEM); 86 return ERR_PTR(-ENOMEM);
83} 87}
84 88
85static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) 89static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx)
86{ 90{
91 spin_lock(&dir->i_lock);
92 list_del(&ctx->list);
93 spin_unlock(&dir->i_lock);
87 put_rpccred(ctx->cred); 94 put_rpccred(ctx->cred);
88 kfree(ctx); 95 kfree(ctx);
89} 96}
@@ -126,7 +133,7 @@ out:
126static int 133static int
127nfs_closedir(struct inode *inode, struct file *filp) 134nfs_closedir(struct inode *inode, struct file *filp)
128{ 135{
129 put_nfs_open_dir_context(filp->private_data); 136 put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data);
130 return 0; 137 return 0;
131} 138}
132 139
@@ -437,6 +444,22 @@ void nfs_advise_use_readdirplus(struct inode *dir)
437 set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); 444 set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags);
438} 445}
439 446
447/*
448 * This function is mainly for use by nfs_getattr().
449 *
450 * If this is an 'ls -l', we want to force use of readdirplus.
451 * Do this by checking if there is an active file descriptor
452 * and calling nfs_advise_use_readdirplus, then forcing a
453 * cache flush.
454 */
455void nfs_force_use_readdirplus(struct inode *dir)
456{
457 if (!list_empty(&NFS_I(dir)->open_files)) {
458 nfs_advise_use_readdirplus(dir);
459 nfs_zap_mapping(dir, dir->i_mapping);
460 }
461}
462
440static 463static
441void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) 464void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
442{ 465{
@@ -815,6 +838,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
815 goto out; 838 goto out;
816} 839}
817 840
841static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
842{
843 struct nfs_inode *nfsi = NFS_I(dir);
844
845 if (nfs_attribute_cache_expired(dir))
846 return true;
847 if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
848 return true;
849 return false;
850}
851
818/* The file offset position represents the dirent entry number. A 852/* The file offset position represents the dirent entry number. A
819 last cookie cache takes care of the common case of reading the 853 last cookie cache takes care of the common case of reading the
820 whole directory. 854 whole directory.
@@ -847,7 +881,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
847 desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; 881 desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
848 882
849 nfs_block_sillyrename(dentry); 883 nfs_block_sillyrename(dentry);
850 if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) 884 if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
851 res = nfs_revalidate_mapping(inode, file->f_mapping); 885 res = nfs_revalidate_mapping(inode, file->f_mapping);
852 if (res < 0) 886 if (res < 0)
853 goto out; 887 goto out;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 360114ae8b82..9dbef878a2b2 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -588,6 +588,25 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
588} 588}
589EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); 589EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
590 590
591static void nfs_request_parent_use_readdirplus(struct dentry *dentry)
592{
593 struct dentry *parent;
594
595 parent = dget_parent(dentry);
596 nfs_force_use_readdirplus(parent->d_inode);
597 dput(parent);
598}
599
600static bool nfs_need_revalidate_inode(struct inode *inode)
601{
602 if (NFS_I(inode)->cache_validity &
603 (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
604 return true;
605 if (nfs_attribute_cache_expired(inode))
606 return true;
607 return false;
608}
609
591int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 610int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
592{ 611{
593 struct inode *inode = dentry->d_inode; 612 struct inode *inode = dentry->d_inode;
@@ -616,10 +635,13 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
616 ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) 635 ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
617 need_atime = 0; 636 need_atime = 0;
618 637
619 if (need_atime) 638 if (need_atime || nfs_need_revalidate_inode(inode)) {
620 err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); 639 struct nfs_server *server = NFS_SERVER(inode);
621 else 640
622 err = nfs_revalidate_inode(NFS_SERVER(inode), inode); 641 if (server->caps & NFS_CAP_READDIRPLUS)
642 nfs_request_parent_use_readdirplus(dentry);
643 err = __nfs_revalidate_inode(server, inode);
644 }
623 if (!err) { 645 if (!err) {
624 generic_fillattr(inode, stat); 646 generic_fillattr(inode, stat);
625 stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); 647 stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
@@ -961,9 +983,7 @@ int nfs_attribute_cache_expired(struct inode *inode)
961 */ 983 */
962int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) 984int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
963{ 985{
964 if (!(NFS_I(inode)->cache_validity & 986 if (!nfs_need_revalidate_inode(inode))
965 (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
966 && !nfs_attribute_cache_expired(inode))
967 return NFS_STALE(inode) ? -ESTALE : 0; 987 return NFS_STALE(inode) ? -ESTALE : 0;
968 return __nfs_revalidate_inode(server, inode); 988 return __nfs_revalidate_inode(server, inode);
969} 989}
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index fafdddac8271..7f7c476d0c2c 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -300,6 +300,7 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
300 const char *ip_addr); 300 const char *ip_addr);
301 301
302/* dir.c */ 302/* dir.c */
303extern void nfs_force_use_readdirplus(struct inode *dir);
303extern unsigned long nfs_access_cache_count(struct shrinker *shrink, 304extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
304 struct shrink_control *sc); 305 struct shrink_control *sc);
305extern unsigned long nfs_access_cache_scan(struct shrinker *shrink, 306extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,