aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-05-31 11:58:49 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-07-20 01:43:03 -0400
commit44396f4b5cb8566f7118aec55eeac99be7ad94cb (patch)
treedc2fd0d01c634ee9a5f5cfb8ca0d660f060ce188 /fs/namei.c
parente6625fa48e6580a74b7e700efd7e6463e282810b (diff)
fs: add a DCACHE_NEED_LOOKUP flag for d_flags
Btrfs (and I'd venture most other fs's) stores its indexes in nice disk order for readdir, but unfortunately in the case of anything that stats the files in order that readdir spits back (like oh say ls) that means we still have to do the normal lookup of the file, which means looking up our other index and then looking up the inode. What I want is a way to create dummy dentries when we find them in readdir so that when ls or anything else subsequently does a stat(), we already have the location information in the dentry and can go straight to the inode itself. The lookup stuff just assumes that if it finds a dentry it is done, it doesn't perform a lookup. So add a DCACHE_NEED_LOOKUP flag so that the lookup code knows it still needs to run i_op->lookup() on the parent to get the inode for the dentry. I have tested this with btrfs and I went from something that looks like this http://people.redhat.com/jwhiter/ls-noreada.png To this http://people.redhat.com/jwhiter/ls-good.png Thats a savings of 1300 seconds, or 22 minutes. That is a significant savings. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 14ab8d3f2f0c..5ba42c453e31 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1134,6 +1134,30 @@ static struct dentry *d_alloc_and_lookup(struct dentry *parent,
1134} 1134}
1135 1135
1136/* 1136/*
1137 * We already have a dentry, but require a lookup to be performed on the parent
1138 * directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error.
1139 * parent->d_inode->i_mutex must be held. d_lookup must have verified that no
1140 * child exists while under i_mutex.
1141 */
1142static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry,
1143 struct nameidata *nd)
1144{
1145 struct inode *inode = parent->d_inode;
1146 struct dentry *old;
1147
1148 /* Don't create child dentry for a dead directory. */
1149 if (unlikely(IS_DEADDIR(inode)))
1150 return ERR_PTR(-ENOENT);
1151
1152 old = inode->i_op->lookup(inode, dentry, nd);
1153 if (unlikely(old)) {
1154 dput(dentry);
1155 dentry = old;
1156 }
1157 return dentry;
1158}
1159
1160/*
1137 * It's more convoluted than I'd like it to be, but... it's still fairly 1161 * It's more convoluted than I'd like it to be, but... it's still fairly
1138 * small and for now I'd prefer to have fast path as straight as possible. 1162 * small and for now I'd prefer to have fast path as straight as possible.
1139 * It _is_ time-critical. 1163 * It _is_ time-critical.
@@ -1172,6 +1196,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
1172 goto unlazy; 1196 goto unlazy;
1173 } 1197 }
1174 } 1198 }
1199 if (unlikely(d_need_lookup(dentry)))
1200 goto unlazy;
1175 path->mnt = mnt; 1201 path->mnt = mnt;
1176 path->dentry = dentry; 1202 path->dentry = dentry;
1177 if (unlikely(!__follow_mount_rcu(nd, path, inode))) 1203 if (unlikely(!__follow_mount_rcu(nd, path, inode)))
@@ -1186,6 +1212,10 @@ unlazy:
1186 dentry = __d_lookup(parent, name); 1212 dentry = __d_lookup(parent, name);
1187 } 1213 }
1188 1214
1215 if (dentry && unlikely(d_need_lookup(dentry))) {
1216 dput(dentry);
1217 dentry = NULL;
1218 }
1189retry: 1219retry:
1190 if (unlikely(!dentry)) { 1220 if (unlikely(!dentry)) {
1191 struct inode *dir = parent->d_inode; 1221 struct inode *dir = parent->d_inode;
@@ -1202,6 +1232,15 @@ retry:
1202 /* known good */ 1232 /* known good */
1203 need_reval = 0; 1233 need_reval = 0;
1204 status = 1; 1234 status = 1;
1235 } else if (unlikely(d_need_lookup(dentry))) {
1236 dentry = d_inode_lookup(parent, dentry, nd);
1237 if (IS_ERR(dentry)) {
1238 mutex_unlock(&dir->i_mutex);
1239 return PTR_ERR(dentry);
1240 }
1241 /* known good */
1242 need_reval = 0;
1243 status = 1;
1205 } 1244 }
1206 mutex_unlock(&dir->i_mutex); 1245 mutex_unlock(&dir->i_mutex);
1207 } 1246 }
@@ -1683,6 +1722,16 @@ static struct dentry *__lookup_hash(struct qstr *name,
1683 */ 1722 */
1684 dentry = d_lookup(base, name); 1723 dentry = d_lookup(base, name);
1685 1724
1725 if (dentry && d_need_lookup(dentry)) {
1726 /*
1727 * __lookup_hash is called with the parent dir's i_mutex already
1728 * held, so we are good to go here.
1729 */
1730 dentry = d_inode_lookup(base, dentry, nd);
1731 if (IS_ERR(dentry))
1732 return dentry;
1733 }
1734
1686 if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) 1735 if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE))
1687 dentry = do_revalidate(dentry, nd); 1736 dentry = do_revalidate(dentry, nd);
1688 1737