Commit 44396f4b5cb8566f7118aec55eeac99be7ad94cb

Authored by Josef Bacik
Committed by Al Viro
1 parent e6625fa48e

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>

Showing 3 changed files with 88 additions and 2 deletions Side-by-side Diff

... ... @@ -344,6 +344,24 @@
344 344 EXPORT_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 + */
  355 +void 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 +}
  362 +EXPORT_SYMBOL(d_clear_need_lookup);
  363 +
  364 +/*
347 365 * Finish off a dentry we've decided to kill.
348 366 * dentry->d_lock must be held, returns with it unlocked.
349 367 * If ref is non-zero, then decrement the refcount too.
... ... @@ -432,8 +450,13 @@
432 450 if (d_unhashed(dentry))
433 451 goto kill_it;
434 452  
435   - /* Otherwise leave it cached and ensure it's on the LRU */
436   - dentry->d_flags |= DCACHE_REFERENCED;
  453 + /*
  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 460 dentry_lru_add(dentry);
438 461  
439 462 dentry->d_count--;
... ... @@ -1706,6 +1729,13 @@
1706 1729 iput(inode);
1707 1730 return found;
1708 1731 }
  1732 +
  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);
1709 1739  
1710 1740 /*
1711 1741 * Negative dentry: instantiate it unless the inode is a directory and
... ... @@ -1134,6 +1134,30 @@
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 + */
  1142 +static 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 1161 * It's more convoluted than I'd like it to be, but... it's still fairly
1138 1162 * small and for now I'd prefer to have fast path as straight as possible.
1139 1163 * It _is_ time-critical.
... ... @@ -1172,6 +1196,8 @@
1172 1196 goto unlazy;
1173 1197 }
1174 1198 }
  1199 + if (unlikely(d_need_lookup(dentry)))
  1200 + goto unlazy;
1175 1201 path->mnt = mnt;
1176 1202 path->dentry = dentry;
1177 1203 if (unlikely(!__follow_mount_rcu(nd, path, inode)))
... ... @@ -1186,6 +1212,10 @@
1186 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 + }
1189 1219 retry:
1190 1220 if (unlikely(!dentry)) {
1191 1221 struct inode *dir = parent->d_inode;
... ... @@ -1202,6 +1232,15 @@
1202 1232 /* known good */
1203 1233 need_reval = 0;
1204 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 1245 mutex_unlock(&dir->i_mutex);
1207 1246 }
... ... @@ -1682,6 +1721,16 @@
1682 1721 * a double lookup.
1683 1722 */
1684 1723 dentry = d_lookup(base, name);
  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 + }
1685 1734  
1686 1735 if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE))
1687 1736 dentry = do_revalidate(dentry, nd);
include/linux/dcache.h
... ... @@ -216,6 +216,7 @@
216 216 #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */
217 217 #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */
218 218 #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */
  219 +#define DCACHE_NEED_LOOKUP 0x80000 /* dentry requires i_op->lookup */
219 220 #define DCACHE_MANAGED_DENTRY \
220 221 (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
221 222  
... ... @@ -416,6 +417,12 @@
416 417 return dentry->d_flags & DCACHE_MOUNTED;
417 418 }
418 419  
  420 +static inline bool d_need_lookup(struct dentry *dentry)
  421 +{
  422 + return dentry->d_flags & DCACHE_NEED_LOOKUP;
  423 +}
  424 +
  425 +extern void d_clear_need_lookup(struct dentry *dentry);
419 426 extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
420 427  
421 428 extern int sysctl_vfs_cache_pressure;