diff options
-rw-r--r-- | fs/dcache.c | 34 | ||||
-rw-r--r-- | fs/namei.c | 49 | ||||
-rw-r--r-- | include/linux/dcache.h | 7 |
3 files changed, 88 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) | |||
344 | EXPORT_SYMBOL(d_drop); | 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 | * 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 | */ | ||
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 | * 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 | } | ||
1189 | retry: | 1219 | retry: |
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 | ||
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 19d90a55541d..5fa5bd33b979 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -216,6 +216,7 @@ struct dentry_operations { | |||
216 | #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ | 216 | #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ |
217 | #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ | 217 | #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ |
218 | #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ | 218 | #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ |
219 | #define DCACHE_NEED_LOOKUP 0x80000 /* dentry requires i_op->lookup */ | ||
219 | #define DCACHE_MANAGED_DENTRY \ | 220 | #define DCACHE_MANAGED_DENTRY \ |
220 | (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) | 221 | (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) |
221 | 222 | ||
@@ -416,6 +417,12 @@ static inline bool d_mountpoint(struct dentry *dentry) | |||
416 | return dentry->d_flags & DCACHE_MOUNTED; | 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 | extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); | 426 | extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); |
420 | 427 | ||
421 | extern int sysctl_vfs_cache_pressure; | 428 | extern int sysctl_vfs_cache_pressure; |