diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-29 16:13:18 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-30 18:02:51 -0400 |
commit | 5c47e6d0ad608987b91affbcf7d1fc12dfbe8fb4 (patch) | |
tree | 5d9845fc2c92f7d5178fcab54cae6cd7426f972c /fs | |
parent | 03b3b889e79cdb6b806fc0ba9be0d71c186bbfaa (diff) |
fold try_prune_one_dentry()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 75 |
1 files changed, 25 insertions, 50 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 9b15c5c37277..a5540d491954 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -787,47 +787,9 @@ restart: | |||
787 | } | 787 | } |
788 | EXPORT_SYMBOL(d_prune_aliases); | 788 | EXPORT_SYMBOL(d_prune_aliases); |
789 | 789 | ||
790 | /* | ||
791 | * Try to throw away a dentry - free the inode, dput the parent. | ||
792 | * Requires dentry->d_lock is held, and dentry->d_count == 0. | ||
793 | * Releases dentry->d_lock. | ||
794 | * | ||
795 | * This may fail if locks cannot be acquired no problem, just try again. | ||
796 | */ | ||
797 | static struct dentry * try_prune_one_dentry(struct dentry *dentry) | ||
798 | __releases(dentry->d_lock) | ||
799 | { | ||
800 | struct dentry *parent; | ||
801 | |||
802 | parent = dentry_kill(dentry, 0); | ||
803 | /* | ||
804 | * If dentry_kill returns NULL, we have nothing more to do. | ||
805 | * if it returns the same dentry, trylocks failed. In either | ||
806 | * case, just loop again. | ||
807 | * | ||
808 | * Otherwise, we need to prune ancestors too. This is necessary | ||
809 | * to prevent quadratic behavior of shrink_dcache_parent(), but | ||
810 | * is also expected to be beneficial in reducing dentry cache | ||
811 | * fragmentation. | ||
812 | */ | ||
813 | if (!parent) | ||
814 | return NULL; | ||
815 | if (parent == dentry) | ||
816 | return dentry; | ||
817 | |||
818 | /* Prune ancestors. */ | ||
819 | dentry = parent; | ||
820 | while (dentry) { | ||
821 | if (lockref_put_or_lock(&dentry->d_lockref)) | ||
822 | return NULL; | ||
823 | dentry = dentry_kill(dentry, 1); | ||
824 | } | ||
825 | return NULL; | ||
826 | } | ||
827 | |||
828 | static void shrink_dentry_list(struct list_head *list) | 790 | static void shrink_dentry_list(struct list_head *list) |
829 | { | 791 | { |
830 | struct dentry *dentry; | 792 | struct dentry *dentry, *parent; |
831 | 793 | ||
832 | rcu_read_lock(); | 794 | rcu_read_lock(); |
833 | for (;;) { | 795 | for (;;) { |
@@ -863,22 +825,35 @@ static void shrink_dentry_list(struct list_head *list) | |||
863 | } | 825 | } |
864 | rcu_read_unlock(); | 826 | rcu_read_unlock(); |
865 | 827 | ||
828 | parent = dentry_kill(dentry, 0); | ||
866 | /* | 829 | /* |
867 | * If 'try_to_prune()' returns a dentry, it will | 830 | * If dentry_kill returns NULL, we have nothing more to do. |
868 | * be the same one we passed in, and d_lock will | ||
869 | * have been held the whole time, so it will not | ||
870 | * have been added to any other lists. We failed | ||
871 | * to get the inode lock. | ||
872 | * | ||
873 | * We just add it back to the shrink list. | ||
874 | */ | 831 | */ |
875 | dentry = try_prune_one_dentry(dentry); | 832 | if (!parent) { |
876 | 833 | rcu_read_lock(); | |
877 | rcu_read_lock(); | 834 | continue; |
878 | if (dentry) { | 835 | } |
836 | if (unlikely(parent == dentry)) { | ||
837 | /* | ||
838 | * trylocks have failed and d_lock has been held the | ||
839 | * whole time, so it could not have been added to any | ||
840 | * other lists. Just add it back to the shrink list. | ||
841 | */ | ||
842 | rcu_read_lock(); | ||
879 | d_shrink_add(dentry, list); | 843 | d_shrink_add(dentry, list); |
880 | spin_unlock(&dentry->d_lock); | 844 | spin_unlock(&dentry->d_lock); |
845 | continue; | ||
881 | } | 846 | } |
847 | /* | ||
848 | * We need to prune ancestors too. This is necessary to prevent | ||
849 | * quadratic behavior of shrink_dcache_parent(), but is also | ||
850 | * expected to be beneficial in reducing dentry cache | ||
851 | * fragmentation. | ||
852 | */ | ||
853 | dentry = parent; | ||
854 | while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) | ||
855 | dentry = dentry_kill(dentry, 1); | ||
856 | rcu_read_lock(); | ||
882 | } | 857 | } |
883 | rcu_read_unlock(); | 858 | rcu_read_unlock(); |
884 | } | 859 | } |