81 lines
3.1 KiB
Plaintext
81 lines
3.1 KiB
Plaintext
|
From: NeilBrown <neilb@suse.de>
|
||
|
Subject: Make selection of 'readdir-plus' adapt to usage patterns.
|
||
|
Patch-mainline: not yet
|
||
|
References: bnc#678123
|
||
|
|
||
|
While the use of READDIRPLUS is significantly more efficient than
|
||
|
READDIR followed by many GETATTR calls, it is still less efficient
|
||
|
than just READDIR if the attributes are not required.
|
||
|
|
||
|
We can get a hint as to whether the application requires attr information
|
||
|
by looking at whether any ->getattr calls are made between
|
||
|
->readdir calls.
|
||
|
If there are any, then getting the attributes seems to be worth while.
|
||
|
|
||
|
This patch tracks whether there have been recent getattr calls on
|
||
|
children of a directory and uses that information to selectively
|
||
|
disable READDIRPLUS on that directory.
|
||
|
|
||
|
The first 'readdir' call is always served using READDIRPLUS.
|
||
|
Subsequent calls only use READDIRPLUS if there was a getattr on a child
|
||
|
in the mean time.
|
||
|
|
||
|
The locking of ->d_parent access needs to be reviewed.
|
||
|
As the bit is simply a hint, it isn't critical that it is set
|
||
|
on the "correct" parent if a rename is happening, but it is
|
||
|
critical that the 'set' doesn't set a bit in something that
|
||
|
isn't even an inode any more.
|
||
|
|
||
|
Acked-by: NeilBrown <neilb@suse.de>
|
||
|
Signed-off-by: Neil Brown <neilb@suse.de>
|
||
|
|
||
|
---
|
||
|
fs/nfs/dir.c | 3 +++
|
||
|
fs/nfs/inode.c | 9 +++++++++
|
||
|
include/linux/nfs_fs.h | 4 ++++
|
||
|
3 files changed, 16 insertions(+)
|
||
|
|
||
|
--- linux-2.6.37-openSUSE-11.4.orig/fs/nfs/dir.c
|
||
|
+++ linux-2.6.37-openSUSE-11.4/fs/nfs/dir.c
|
||
|
@@ -802,6 +802,9 @@ static int nfs_readdir(struct file *filp
|
||
|
desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;
|
||
|
desc->decode = NFS_PROTO(inode)->decode_dirent;
|
||
|
desc->plus = NFS_USE_READDIRPLUS(inode);
|
||
|
+ if (filp->f_pos > 0 && !test_bit(NFS_INO_SEEN_GETATTR, &NFS_I(inode)->flags))
|
||
|
+ desc->plus = 0;
|
||
|
+ clear_bit(NFS_INO_SEEN_GETATTR, &NFS_I(inode)->flags);
|
||
|
|
||
|
nfs_block_sillyrename(dentry);
|
||
|
res = nfs_revalidate_mapping(inode, filp->f_mapping);
|
||
|
--- linux-2.6.37-openSUSE-11.4.orig/fs/nfs/inode.c
|
||
|
+++ linux-2.6.37-openSUSE-11.4/fs/nfs/inode.c
|
||
|
@@ -500,6 +500,15 @@ int nfs_getattr(struct vfsmount *mnt, st
|
||
|
struct inode *inode = dentry->d_inode;
|
||
|
int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
|
||
|
int err;
|
||
|
+ struct dentry *p;
|
||
|
+ struct inode *pi;
|
||
|
+
|
||
|
+ rcu_read_lock();
|
||
|
+ p = dentry->d_parent;
|
||
|
+ pi = rcu_dereference(p)->d_inode;
|
||
|
+ if (pi && !test_bit(NFS_INO_SEEN_GETATTR, &NFS_I(pi)->flags))
|
||
|
+ set_bit(NFS_INO_SEEN_GETATTR, &NFS_I(pi)->flags);
|
||
|
+ rcu_read_unlock();
|
||
|
|
||
|
/* Flush out writes to the server in order to update c/mtime. */
|
||
|
if (S_ISREG(inode->i_mode)) {
|
||
|
--- linux-2.6.37-openSUSE-11.4.orig/include/linux/nfs_fs.h
|
||
|
+++ linux-2.6.37-openSUSE-11.4/include/linux/nfs_fs.h
|
||
|
@@ -220,6 +220,10 @@ struct nfs_inode {
|
||
|
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
|
||
|
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
|
||
|
#define NFS_INO_COMMIT (7) /* inode is committing unstable writes */
|
||
|
+#define NFS_INO_SEEN_GETATTR (8) /* flag to track if app is calling
|
||
|
+ * getattr in a directory during
|
||
|
+ * readdir
|
||
|
+ */
|
||
|
|
||
|
static inline struct nfs_inode *NFS_I(const struct inode *inode)
|
||
|
{
|