diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 106 |
1 files changed, 58 insertions, 48 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 9791b1e7eee4..16a53cc2cc02 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -243,6 +243,7 @@ static void dentry_lru_add(struct dentry *dentry) | |||
243 | static void __dentry_lru_del(struct dentry *dentry) | 243 | static void __dentry_lru_del(struct dentry *dentry) |
244 | { | 244 | { |
245 | list_del_init(&dentry->d_lru); | 245 | list_del_init(&dentry->d_lru); |
246 | dentry->d_flags &= ~DCACHE_SHRINK_LIST; | ||
246 | dentry->d_sb->s_nr_dentry_unused--; | 247 | dentry->d_sb->s_nr_dentry_unused--; |
247 | dentry_stat.nr_unused--; | 248 | dentry_stat.nr_unused--; |
248 | } | 249 | } |
@@ -276,15 +277,15 @@ static void dentry_lru_prune(struct dentry *dentry) | |||
276 | } | 277 | } |
277 | } | 278 | } |
278 | 279 | ||
279 | static void dentry_lru_move_tail(struct dentry *dentry) | 280 | static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list) |
280 | { | 281 | { |
281 | spin_lock(&dcache_lru_lock); | 282 | spin_lock(&dcache_lru_lock); |
282 | if (list_empty(&dentry->d_lru)) { | 283 | if (list_empty(&dentry->d_lru)) { |
283 | list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); | 284 | list_add_tail(&dentry->d_lru, list); |
284 | dentry->d_sb->s_nr_dentry_unused++; | 285 | dentry->d_sb->s_nr_dentry_unused++; |
285 | dentry_stat.nr_unused++; | 286 | dentry_stat.nr_unused++; |
286 | } else { | 287 | } else { |
287 | list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); | 288 | list_move_tail(&dentry->d_lru, list); |
288 | } | 289 | } |
289 | spin_unlock(&dcache_lru_lock); | 290 | spin_unlock(&dcache_lru_lock); |
290 | } | 291 | } |
@@ -770,14 +771,18 @@ static void shrink_dentry_list(struct list_head *list) | |||
770 | } | 771 | } |
771 | 772 | ||
772 | /** | 773 | /** |
773 | * __shrink_dcache_sb - shrink the dentry LRU on a given superblock | 774 | * prune_dcache_sb - shrink the dcache |
774 | * @sb: superblock to shrink dentry LRU. | 775 | * @sb: superblock |
775 | * @count: number of entries to prune | 776 | * @count: number of entries to try to free |
776 | * @flags: flags to control the dentry processing | 777 | * |
778 | * Attempt to shrink the superblock dcache LRU by @count entries. This is | ||
779 | * done when we need more memory an called from the superblock shrinker | ||
780 | * function. | ||
777 | * | 781 | * |
778 | * If flags contains DCACHE_REFERENCED reference dentries will not be pruned. | 782 | * This function may fail to free any resources if all the dentries are in |
783 | * use. | ||
779 | */ | 784 | */ |
780 | static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) | 785 | void prune_dcache_sb(struct super_block *sb, int count) |
781 | { | 786 | { |
782 | struct dentry *dentry; | 787 | struct dentry *dentry; |
783 | LIST_HEAD(referenced); | 788 | LIST_HEAD(referenced); |
@@ -796,18 +801,13 @@ relock: | |||
796 | goto relock; | 801 | goto relock; |
797 | } | 802 | } |
798 | 803 | ||
799 | /* | 804 | if (dentry->d_flags & DCACHE_REFERENCED) { |
800 | * If we are honouring the DCACHE_REFERENCED flag and the | ||
801 | * dentry has this flag set, don't free it. Clear the flag | ||
802 | * and put it back on the LRU. | ||
803 | */ | ||
804 | if (flags & DCACHE_REFERENCED && | ||
805 | dentry->d_flags & DCACHE_REFERENCED) { | ||
806 | dentry->d_flags &= ~DCACHE_REFERENCED; | 805 | dentry->d_flags &= ~DCACHE_REFERENCED; |
807 | list_move(&dentry->d_lru, &referenced); | 806 | list_move(&dentry->d_lru, &referenced); |
808 | spin_unlock(&dentry->d_lock); | 807 | spin_unlock(&dentry->d_lock); |
809 | } else { | 808 | } else { |
810 | list_move_tail(&dentry->d_lru, &tmp); | 809 | list_move_tail(&dentry->d_lru, &tmp); |
810 | dentry->d_flags |= DCACHE_SHRINK_LIST; | ||
811 | spin_unlock(&dentry->d_lock); | 811 | spin_unlock(&dentry->d_lock); |
812 | if (!--count) | 812 | if (!--count) |
813 | break; | 813 | break; |
@@ -822,23 +822,6 @@ relock: | |||
822 | } | 822 | } |
823 | 823 | ||
824 | /** | 824 | /** |
825 | * prune_dcache_sb - shrink the dcache | ||
826 | * @sb: superblock | ||
827 | * @nr_to_scan: number of entries to try to free | ||
828 | * | ||
829 | * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is | ||
830 | * done when we need more memory an called from the superblock shrinker | ||
831 | * function. | ||
832 | * | ||
833 | * This function may fail to free any resources if all the dentries are in | ||
834 | * use. | ||
835 | */ | ||
836 | void prune_dcache_sb(struct super_block *sb, int nr_to_scan) | ||
837 | { | ||
838 | __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED); | ||
839 | } | ||
840 | |||
841 | /** | ||
842 | * shrink_dcache_sb - shrink dcache for a superblock | 825 | * shrink_dcache_sb - shrink dcache for a superblock |
843 | * @sb: superblock | 826 | * @sb: superblock |
844 | * | 827 | * |
@@ -1092,7 +1075,7 @@ EXPORT_SYMBOL(have_submounts); | |||
1092 | * drop the lock and return early due to latency | 1075 | * drop the lock and return early due to latency |
1093 | * constraints. | 1076 | * constraints. |
1094 | */ | 1077 | */ |
1095 | static int select_parent(struct dentry * parent) | 1078 | static int select_parent(struct dentry *parent, struct list_head *dispose) |
1096 | { | 1079 | { |
1097 | struct dentry *this_parent; | 1080 | struct dentry *this_parent; |
1098 | struct list_head *next; | 1081 | struct list_head *next; |
@@ -1114,17 +1097,21 @@ resume: | |||
1114 | 1097 | ||
1115 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | 1098 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1116 | 1099 | ||
1117 | /* | 1100 | /* |
1118 | * move only zero ref count dentries to the end | 1101 | * move only zero ref count dentries to the dispose list. |
1119 | * of the unused list for prune_dcache | 1102 | * |
1103 | * Those which are presently on the shrink list, being processed | ||
1104 | * by shrink_dentry_list(), shouldn't be moved. Otherwise the | ||
1105 | * loop in shrink_dcache_parent() might not make any progress | ||
1106 | * and loop forever. | ||
1120 | */ | 1107 | */ |
1121 | if (!dentry->d_count) { | 1108 | if (dentry->d_count) { |
1122 | dentry_lru_move_tail(dentry); | ||
1123 | found++; | ||
1124 | } else { | ||
1125 | dentry_lru_del(dentry); | 1109 | dentry_lru_del(dentry); |
1110 | } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { | ||
1111 | dentry_lru_move_list(dentry, dispose); | ||
1112 | dentry->d_flags |= DCACHE_SHRINK_LIST; | ||
1113 | found++; | ||
1126 | } | 1114 | } |
1127 | |||
1128 | /* | 1115 | /* |
1129 | * We can return to the caller if we have found some (this | 1116 | * We can return to the caller if we have found some (this |
1130 | * ensures forward progress). We'll be coming back to find | 1117 | * ensures forward progress). We'll be coming back to find |
@@ -1181,14 +1168,13 @@ rename_retry: | |||
1181 | * | 1168 | * |
1182 | * Prune the dcache to remove unused children of the parent dentry. | 1169 | * Prune the dcache to remove unused children of the parent dentry. |
1183 | */ | 1170 | */ |
1184 | |||
1185 | void shrink_dcache_parent(struct dentry * parent) | 1171 | void shrink_dcache_parent(struct dentry * parent) |
1186 | { | 1172 | { |
1187 | struct super_block *sb = parent->d_sb; | 1173 | LIST_HEAD(dispose); |
1188 | int found; | 1174 | int found; |
1189 | 1175 | ||
1190 | while ((found = select_parent(parent)) != 0) | 1176 | while ((found = select_parent(parent, &dispose)) != 0) |
1191 | __shrink_dcache_sb(sb, found, 0); | 1177 | shrink_dentry_list(&dispose); |
1192 | } | 1178 | } |
1193 | EXPORT_SYMBOL(shrink_dcache_parent); | 1179 | EXPORT_SYMBOL(shrink_dcache_parent); |
1194 | 1180 | ||
@@ -1461,6 +1447,23 @@ struct dentry * d_alloc_root(struct inode * root_inode) | |||
1461 | } | 1447 | } |
1462 | EXPORT_SYMBOL(d_alloc_root); | 1448 | EXPORT_SYMBOL(d_alloc_root); |
1463 | 1449 | ||
1450 | struct dentry *d_make_root(struct inode *root_inode) | ||
1451 | { | ||
1452 | struct dentry *res = NULL; | ||
1453 | |||
1454 | if (root_inode) { | ||
1455 | static const struct qstr name = { .name = "/", .len = 1 }; | ||
1456 | |||
1457 | res = __d_alloc(root_inode->i_sb, &name); | ||
1458 | if (res) | ||
1459 | d_instantiate(res, root_inode); | ||
1460 | else | ||
1461 | iput(root_inode); | ||
1462 | } | ||
1463 | return res; | ||
1464 | } | ||
1465 | EXPORT_SYMBOL(d_make_root); | ||
1466 | |||
1464 | static struct dentry * __d_find_any_alias(struct inode *inode) | 1467 | static struct dentry * __d_find_any_alias(struct inode *inode) |
1465 | { | 1468 | { |
1466 | struct dentry *alias; | 1469 | struct dentry *alias; |
@@ -1472,7 +1475,14 @@ static struct dentry * __d_find_any_alias(struct inode *inode) | |||
1472 | return alias; | 1475 | return alias; |
1473 | } | 1476 | } |
1474 | 1477 | ||
1475 | static struct dentry * d_find_any_alias(struct inode *inode) | 1478 | /** |
1479 | * d_find_any_alias - find any alias for a given inode | ||
1480 | * @inode: inode to find an alias for | ||
1481 | * | ||
1482 | * If any aliases exist for the given inode, take and return a | ||
1483 | * reference for one of them. If no aliases exist, return %NULL. | ||
1484 | */ | ||
1485 | struct dentry *d_find_any_alias(struct inode *inode) | ||
1476 | { | 1486 | { |
1477 | struct dentry *de; | 1487 | struct dentry *de; |
1478 | 1488 | ||
@@ -1481,7 +1491,7 @@ static struct dentry * d_find_any_alias(struct inode *inode) | |||
1481 | spin_unlock(&inode->i_lock); | 1491 | spin_unlock(&inode->i_lock); |
1482 | return de; | 1492 | return de; |
1483 | } | 1493 | } |
1484 | 1494 | EXPORT_SYMBOL(d_find_any_alias); | |
1485 | 1495 | ||
1486 | /** | 1496 | /** |
1487 | * d_obtain_alias - find or allocate a dentry for a given inode | 1497 | * d_obtain_alias - find or allocate a dentry for a given inode |