aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/dcache.c34
-rw-r--r--fs/namei.c49
2 files changed, 81 insertions, 2 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 6e4ea6d87774..d3902139b533 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -344,6 +344,24 @@ void d_drop(struct dentry *dentry)
344EXPORT_SYMBOL(d_drop); 344EXPORT_SYMBOL(d_drop);
345 345
346/* 346/*
347 * d_clear_need_lookup - drop a dentry from cache and clear the need lookup flag
348 * @dentry: dentry to drop
349 *
350 * This is called when we do a lookup on a placeholder dentry that needed to be
351 * looked up. The dentry should have been hashed in order for it to be found by
352 * the lookup code, but now needs to be unhashed while we do the actual lookup
353 * and clear the DCACHE_NEED_LOOKUP flag.
354 */
355void d_clear_need_lookup(struct dentry *dentry)
356{
357 spin_lock(&dentry->d_lock);
358 __d_drop(dentry);
359 dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
360 spin_unlock(&dentry->d_lock);
361}
362EXPORT_SYMBOL(d_clear_need_lookup);
363
364/*
347 * Finish off a dentry we've decided to kill. 365 * Finish off a dentry we've decided to kill.
348 * dentry->d_lock must be held, returns with it unlocked. 366 * dentry->d_lock must be held, returns with it unlocked.
349 * If ref is non-zero, then decrement the refcount too. 367 * If ref is non-zero, then decrement the refcount too.
@@ -432,8 +450,13 @@ repeat:
432 if (d_unhashed(dentry)) 450 if (d_unhashed(dentry))
433 goto kill_it; 451 goto kill_it;
434 452
435 /* Otherwise leave it cached and ensure it's on the LRU */ 453 /*
436 dentry->d_flags |= DCACHE_REFERENCED; 454 * If this dentry needs lookup, don't set the referenced flag so that it
455 * is more likely to be cleaned up by the dcache shrinker in case of
456 * memory pressure.
457 */
458 if (!d_need_lookup(dentry))
459 dentry->d_flags |= DCACHE_REFERENCED;
437 dentry_lru_add(dentry); 460 dentry_lru_add(dentry);
438 461
439 dentry->d_count--; 462 dentry->d_count--;
@@ -1708,6 +1731,13 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
1708 } 1731 }
1709 1732
1710 /* 1733 /*
1734 * We are going to instantiate this dentry, unhash it and clear the
1735 * lookup flag so we can do that.
1736 */
1737 if (unlikely(d_need_lookup(found)))
1738 d_clear_need_lookup(found);
1739
1740 /*
1711 * Negative dentry: instantiate it unless the inode is a directory and 1741 * Negative dentry: instantiate it unless the inode is a directory and
1712 * already has a dentry. 1742 * already has a dentry.
1713 */ 1743 */
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