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 | |
| parent | 03b3b889e79cdb6b806fc0ba9be0d71c186bbfaa (diff) | |
fold try_prune_one_dentry()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -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 | } |
