aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2011-08-23 04:56:24 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-01-09 19:22:52 -0500
commitb48f03b319ba78f3abf9a7044d1f436d8d90f4f9 (patch)
tree7ddc8f545787d28825413946519ed88ea19edb24 /fs/dcache.c
parent3c5184ef1216dd476c9c67f22a199d90ac4d5892 (diff)
dcache: use a dispose list in select_parent
select_parent currently abuses the dentry cache LRU to provide cleanup features for child dentries that need to be freed. It moves them to the tail of the LRU, then tells shrink_dcache_parent() to calls __shrink_dcache_sb to unconditionally move them to a dispose list (as DCACHE_REFERENCED is ignored). __shrink_dcache_sb() has to relock the dentries to move them off the LRU onto the dispose list, but otherwise does not touch the dentries that select_parent() moved to the tail of the LRU. It then passses the dispose list to shrink_dentry_list() which tries to free the dentries. IOWs, the use of __shrink_dcache_sb() is superfluous - we can build exactly the same list of dentries for disposal directly in select_parent() and call shrink_dentry_list() instead of calling __shrink_dcache_sb() to do that. This means that we avoid long holds on the lru lock walking the LRU moving dentries to the dispose list We also avoid the need to relock each dentry just to move it off the LRU, reducing the numebr of times we lock each dentry to dispose of them in shrink_dcache_parent() from 3 to 2 times. Further, we remove one of the two callers of __shrink_dcache_sb(). This also means that __shrink_dcache_sb can be moved into back into prune_dcache_sb() and we no longer have to handle referenced dentries conditionally, simplifying the code. Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c63
1 files changed, 21 insertions, 42 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 9791b1e7eee4..b209d73f9a98 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -276,15 +276,15 @@ static void dentry_lru_prune(struct dentry *dentry)
276 } 276 }
277} 277}
278 278
279static void dentry_lru_move_tail(struct dentry *dentry) 279static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
280{ 280{
281 spin_lock(&dcache_lru_lock); 281 spin_lock(&dcache_lru_lock);
282 if (list_empty(&dentry->d_lru)) { 282 if (list_empty(&dentry->d_lru)) {
283 list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); 283 list_add_tail(&dentry->d_lru, list);
284 dentry->d_sb->s_nr_dentry_unused++; 284 dentry->d_sb->s_nr_dentry_unused++;
285 dentry_stat.nr_unused++; 285 dentry_stat.nr_unused++;
286 } else { 286 } else {
287 list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); 287 list_move_tail(&dentry->d_lru, list);
288 } 288 }
289 spin_unlock(&dcache_lru_lock); 289 spin_unlock(&dcache_lru_lock);
290} 290}
@@ -770,14 +770,18 @@ static void shrink_dentry_list(struct list_head *list)
770} 770}
771 771
772/** 772/**
773 * __shrink_dcache_sb - shrink the dentry LRU on a given superblock 773 * prune_dcache_sb - shrink the dcache
774 * @sb: superblock to shrink dentry LRU. 774 * @sb: superblock
775 * @count: number of entries to prune 775 * @count: number of entries to try to free
776 * @flags: flags to control the dentry processing 776 *
777 * Attempt to shrink the superblock dcache LRU by @count entries. This is
778 * done when we need more memory an called from the superblock shrinker
779 * function.
777 * 780 *
778 * If flags contains DCACHE_REFERENCED reference dentries will not be pruned. 781 * This function may fail to free any resources if all the dentries are in
782 * use.
779 */ 783 */
780static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) 784void prune_dcache_sb(struct super_block *sb, int count)
781{ 785{
782 struct dentry *dentry; 786 struct dentry *dentry;
783 LIST_HEAD(referenced); 787 LIST_HEAD(referenced);
@@ -796,13 +800,7 @@ relock:
796 goto relock; 800 goto relock;
797 } 801 }
798 802
799 /* 803 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; 804 dentry->d_flags &= ~DCACHE_REFERENCED;
807 list_move(&dentry->d_lru, &referenced); 805 list_move(&dentry->d_lru, &referenced);
808 spin_unlock(&dentry->d_lock); 806 spin_unlock(&dentry->d_lock);
@@ -822,23 +820,6 @@ relock:
822} 820}
823 821
824/** 822/**
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 */
836void 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 823 * shrink_dcache_sb - shrink dcache for a superblock
843 * @sb: superblock 824 * @sb: superblock
844 * 825 *
@@ -1092,7 +1073,7 @@ EXPORT_SYMBOL(have_submounts);
1092 * drop the lock and return early due to latency 1073 * drop the lock and return early due to latency
1093 * constraints. 1074 * constraints.
1094 */ 1075 */
1095static int select_parent(struct dentry * parent) 1076static int select_parent(struct dentry *parent, struct list_head *dispose)
1096{ 1077{
1097 struct dentry *this_parent; 1078 struct dentry *this_parent;
1098 struct list_head *next; 1079 struct list_head *next;
@@ -1114,12 +1095,11 @@ resume:
1114 1095
1115 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 1096 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
1116 1097
1117 /* 1098 /*
1118 * move only zero ref count dentries to the end 1099 * move only zero ref count dentries to the dispose list.
1119 * of the unused list for prune_dcache
1120 */ 1100 */
1121 if (!dentry->d_count) { 1101 if (!dentry->d_count) {
1122 dentry_lru_move_tail(dentry); 1102 dentry_lru_move_list(dentry, dispose);
1123 found++; 1103 found++;
1124 } else { 1104 } else {
1125 dentry_lru_del(dentry); 1105 dentry_lru_del(dentry);
@@ -1181,14 +1161,13 @@ rename_retry:
1181 * 1161 *
1182 * Prune the dcache to remove unused children of the parent dentry. 1162 * Prune the dcache to remove unused children of the parent dentry.
1183 */ 1163 */
1184
1185void shrink_dcache_parent(struct dentry * parent) 1164void shrink_dcache_parent(struct dentry * parent)
1186{ 1165{
1187 struct super_block *sb = parent->d_sb; 1166 LIST_HEAD(dispose);
1188 int found; 1167 int found;
1189 1168
1190 while ((found = select_parent(parent)) != 0) 1169 while ((found = select_parent(parent, &dispose)) != 0)
1191 __shrink_dcache_sb(sb, found, 0); 1170 shrink_dentry_list(&dispose);
1192} 1171}
1193EXPORT_SYMBOL(shrink_dcache_parent); 1172EXPORT_SYMBOL(shrink_dcache_parent);
1194 1173