diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index a88948b8bd17..274f13e2f094 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -225,7 +225,7 @@ static void dentry_unlink_inode(struct dentry * dentry) | |||
225 | } | 225 | } |
226 | 226 | ||
227 | /* | 227 | /* |
228 | * dentry_lru_(add|del|move_tail) must be called with d_lock held. | 228 | * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held. |
229 | */ | 229 | */ |
230 | static void dentry_lru_add(struct dentry *dentry) | 230 | static void dentry_lru_add(struct dentry *dentry) |
231 | { | 231 | { |
@@ -245,6 +245,9 @@ static void __dentry_lru_del(struct dentry *dentry) | |||
245 | dentry_stat.nr_unused--; | 245 | dentry_stat.nr_unused--; |
246 | } | 246 | } |
247 | 247 | ||
248 | /* | ||
249 | * Remove a dentry with references from the LRU. | ||
250 | */ | ||
248 | static void dentry_lru_del(struct dentry *dentry) | 251 | static void dentry_lru_del(struct dentry *dentry) |
249 | { | 252 | { |
250 | if (!list_empty(&dentry->d_lru)) { | 253 | if (!list_empty(&dentry->d_lru)) { |
@@ -254,6 +257,23 @@ static void dentry_lru_del(struct dentry *dentry) | |||
254 | } | 257 | } |
255 | } | 258 | } |
256 | 259 | ||
260 | /* | ||
261 | * Remove a dentry that is unreferenced and about to be pruned | ||
262 | * (unhashed and destroyed) from the LRU, and inform the file system. | ||
263 | * This wrapper should be called _prior_ to unhashing a victim dentry. | ||
264 | */ | ||
265 | static void dentry_lru_prune(struct dentry *dentry) | ||
266 | { | ||
267 | if (!list_empty(&dentry->d_lru)) { | ||
268 | if (dentry->d_flags & DCACHE_OP_PRUNE) | ||
269 | dentry->d_op->d_prune(dentry); | ||
270 | |||
271 | spin_lock(&dcache_lru_lock); | ||
272 | __dentry_lru_del(dentry); | ||
273 | spin_unlock(&dcache_lru_lock); | ||
274 | } | ||
275 | } | ||
276 | |||
257 | static void dentry_lru_move_tail(struct dentry *dentry) | 277 | static void dentry_lru_move_tail(struct dentry *dentry) |
258 | { | 278 | { |
259 | spin_lock(&dcache_lru_lock); | 279 | spin_lock(&dcache_lru_lock); |
@@ -403,8 +423,12 @@ relock: | |||
403 | 423 | ||
404 | if (ref) | 424 | if (ref) |
405 | dentry->d_count--; | 425 | dentry->d_count--; |
406 | /* if dentry was on the d_lru list delete it from there */ | 426 | /* |
407 | dentry_lru_del(dentry); | 427 | * if dentry was on the d_lru list delete it from there. |
428 | * inform the fs via d_prune that this dentry is about to be | ||
429 | * unhashed and destroyed. | ||
430 | */ | ||
431 | dentry_lru_prune(dentry); | ||
408 | /* if it was on the hash then remove it */ | 432 | /* if it was on the hash then remove it */ |
409 | __d_drop(dentry); | 433 | __d_drop(dentry); |
410 | return d_kill(dentry, parent); | 434 | return d_kill(dentry, parent); |
@@ -854,8 +878,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
854 | do { | 878 | do { |
855 | struct inode *inode; | 879 | struct inode *inode; |
856 | 880 | ||
857 | /* detach from the system */ | 881 | /* |
858 | dentry_lru_del(dentry); | 882 | * remove the dentry from the lru, and inform |
883 | * the fs that this dentry is about to be | ||
884 | * unhashed and destroyed. | ||
885 | */ | ||
886 | dentry_lru_prune(dentry); | ||
859 | __d_shrink(dentry); | 887 | __d_shrink(dentry); |
860 | 888 | ||
861 | if (dentry->d_count != 0) { | 889 | if (dentry->d_count != 0) { |
@@ -1283,6 +1311,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1283 | dentry->d_flags |= DCACHE_OP_REVALIDATE; | 1311 | dentry->d_flags |= DCACHE_OP_REVALIDATE; |
1284 | if (op->d_delete) | 1312 | if (op->d_delete) |
1285 | dentry->d_flags |= DCACHE_OP_DELETE; | 1313 | dentry->d_flags |= DCACHE_OP_DELETE; |
1314 | if (op->d_prune) | ||
1315 | dentry->d_flags |= DCACHE_OP_PRUNE; | ||
1286 | 1316 | ||
1287 | } | 1317 | } |
1288 | EXPORT_SYMBOL(d_set_d_op); | 1318 | EXPORT_SYMBOL(d_set_d_op); |