| @@ -67,6 +67,19 @@ struct dentry_stat_t dentry_stat = { · 66 unmodified lines |
| 67 | 67 | .age_limit = 45, |
| 68 | 68 | }; |
| 69 | 69 | |
| 70 | +static struct percpu_counter nr_dentry __cacheline_aligned_in_smp; |
| 71 | +static struct percpu_counter nr_dentry_unused __cacheline_aligned_in_smp; |
| 72 | + |
| 73 | +#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) |
| 74 | +int proc_nr_dentry(ctl_table *table, int write, void __user *buffer, |
| 75 | + size_t *lenp, loff_t *ppos) |
| 76 | +{ |
| 77 | + dentry_stat.nr_dentry = percpu_counter_sum_positive(&nr_dentry); |
| 78 | + dentry_stat.nr_unused = percpu_counter_sum_positive(&nr_dentry_unused); |
| 79 | + return proc_dointvec(table, write, buffer, lenp, ppos); |
| 80 | +} |
| 81 | +#endif |
| 82 | + |
| 70 | 83 | static void __d_free(struct rcu_head *head) |
| 71 | 84 | { |
| 72 | 85 | struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); |
| @@ -78,13 +91,14 @@ static void __d_free(struct rcu_head *head) · 5 unmodified lines |
| 78 | 91 | } |
| 79 | 92 | |
| 80 | 93 | /* |
| 81 | | − * no dcache_lock, please. The caller must decrement dentry_stat.nr_dentry |
| 82 | | − * inside dcache_lock. |
| 94 | + * no dcache_lock, please. |
| 83 | 95 | */ |
| 84 | 96 | static void d_free(struct dentry *dentry) |
| 85 | 97 | { |
| 98 | + percpu_counter_dec(&nr_dentry); |
| 86 | 99 | if (dentry->d_op && dentry->d_op->d_release) |
| 87 | 100 | dentry->d_op->d_release(dentry); |
| 101 | + |
| 88 | 102 | /* if dentry was never inserted into hash, immediate free is OK */ |
| 89 | 103 | if (hlist_unhashed(&dentry->d_hash)) |
| 90 | 104 | __d_free(&dentry->d_u.d_rcu); |
| @@ -125,14 +139,14 @@ static void dentry_lru_add(struct dentry *dentry) · 34 unmodified lines |
| 125 | 139 | { |
| 126 | 140 | list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); |
| 127 | 141 | dentry->d_sb->s_nr_dentry_unused++; |
| 128 | | − dentry_stat.nr_unused++; |
| 142 | + percpu_counter_inc(&nr_dentry_unused); |
| 129 | 143 | } |
| 130 | 144 | |
| 131 | 145 | static void dentry_lru_add_tail(struct dentry *dentry) |
| 132 | 146 | { |
| 133 | 147 | list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); |
| 134 | 148 | dentry->d_sb->s_nr_dentry_unused++; |
| 135 | | − dentry_stat.nr_unused++; |
| 149 | + percpu_counter_inc(&nr_dentry_unused); |
| 136 | 150 | } |
| 137 | 151 | |
| 138 | 152 | static void dentry_lru_del(struct dentry *dentry) |
| @@ -140,7 +154,7 @@ static void dentry_lru_del(struct dentry *dentry) · 1 unmodified line |
| 140 | 154 | if (!list_empty(&dentry->d_lru)) { |
| 141 | 155 | list_del(&dentry->d_lru); |
| 142 | 156 | dentry->d_sb->s_nr_dentry_unused--; |
| 143 | | − dentry_stat.nr_unused--; |
| 157 | + percpu_counter_dec(&nr_dentry_unused); |
| 144 | 158 | } |
| 145 | 159 | } |
| 146 | 160 | |
| @@ -149,7 +163,7 @@ static void dentry_lru_del_init(struct dentry *dentry) · 2 unmodified lines |
| 149 | 163 | if (likely(!list_empty(&dentry->d_lru))) { |
| 150 | 164 | list_del_init(&dentry->d_lru); |
| 151 | 165 | dentry->d_sb->s_nr_dentry_unused--; |
| 152 | | − dentry_stat.nr_unused--; |
| 166 | + percpu_counter_dec(&nr_dentry_unused); |
| 153 | 167 | } |
| 154 | 168 | } |
| 155 | 169 | |
| @@ -168,7 +182,6 @@ static struct dentry *d_kill(struct dentry *dentry) · 12 unmodified lines |
| 168 | 182 | struct dentry *parent; |
| 169 | 183 | |
| 170 | 184 | list_del(&dentry->d_u.d_child); |
| 171 | | − dentry_stat.nr_dentry--; /* For d_free, below */ |
| 172 | 185 | /*drops the locks, at that point nobody can reach this dentry */ |
| 173 | 186 | dentry_iput(dentry); |
| 174 | 187 | if (IS_ROOT(dentry)) |
| @@ -314,7 +327,6 @@ int d_invalidate(struct dentry * dentry) · 139 unmodified lines |
| 314 | 327 | EXPORT_SYMBOL(d_invalidate); |
| 315 | 328 | |
| 316 | 329 | /* This should be called _only_ with dcache_lock held */ |
| 317 | | − |
| 318 | 330 | static inline struct dentry * __dget_locked(struct dentry *dentry) |
| 319 | 331 | { |
| 320 | 332 | atomic_inc(&dentry->d_count); |
| @@ -534,7 +546,7 @@ static void prune_dcache(int count) · 213 unmodified lines |
| 534 | 546 | { |
| 535 | 547 | struct super_block *sb, *p = NULL; |
| 536 | 548 | int w_count; |
| 537 | | − int unused = dentry_stat.nr_unused; |
| 549 | + int unused = percpu_counter_sum_positive(&nr_dentry_unused); |
| 538 | 550 | int prune_ratio; |
| 539 | 551 | int pruned; |
| 540 | 552 | |
| @@ -699,20 +711,13 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) · 158 unmodified lines |
| 699 | 711 | * otherwise we ascend to the parent and move to the |
| 700 | 712 | * next sibling if there is one */ |
| 701 | 713 | if (!parent) |
| 702 | | − goto out; |
| 703 | | − |
| 714 | + return; |
| 704 | 715 | dentry = parent; |
| 705 | | − |
| 706 | 716 | } while (list_empty(&dentry->d_subdirs)); |
| 707 | 717 | |
| 708 | 718 | dentry = list_entry(dentry->d_subdirs.next, |
| 709 | 719 | struct dentry, d_u.d_child); |
| 710 | 720 | } |
| 711 | | −out: |
| 712 | | − /* several dentries were freed, need to correct nr_dentry */ |
| 713 | | − spin_lock(&dcache_lock); |
| 714 | | − dentry_stat.nr_dentry -= detached; |
| 715 | | − spin_unlock(&dcache_lock); |
| 716 | 721 | } |
| 717 | 722 | |
| 718 | 723 | /* |
| @@ -896,12 +901,16 @@ EXPORT_SYMBOL(shrink_dcache_parent); · 177 unmodified lines |
| 896 | 901 | */ |
| 897 | 902 | static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask) |
| 898 | 903 | { |
| 904 | + int nr_unused; |
| 905 | + |
| 899 | 906 | if (nr) { |
| 900 | 907 | if (!(gfp_mask & __GFP_FS)) |
| 901 | 908 | return -1; |
| 902 | 909 | prune_dcache(nr); |
| 903 | 910 | } |
| 904 | | − return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; |
| 911 | + |
| 912 | + nr_unused = percpu_counter_sum_positive(&nr_dentry_unused); |
| 913 | + return (nr_unused / 100) * sysctl_vfs_cache_pressure; |
| 905 | 914 | } |
| 906 | 915 | |
| 907 | 916 | static struct shrinker dcache_shrinker = { |
| @@ -968,9 +977,10 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) · 60 unmodified lines |
| 968 | 977 | spin_lock(&dcache_lock); |
| 969 | 978 | if (parent) |
| 970 | 979 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); |
| 971 | | − dentry_stat.nr_dentry++; |
| 972 | 980 | spin_unlock(&dcache_lock); |
| 973 | 981 | |
| 982 | + percpu_counter_inc(&nr_dentry); |
| 983 | + |
| 974 | 984 | return dentry; |
| 975 | 985 | } |
| 976 | 986 | EXPORT_SYMBOL(d_alloc); |
| @@ -2417,6 +2427,9 @@ static void __init dcache_init(void) · 1440 unmodified lines |
| 2417 | 2427 | { |
| 2418 | 2428 | int loop; |
| 2419 | 2429 | |
| 2430 | + percpu_counter_init(&nr_dentry, 0); |
| 2431 | + percpu_counter_init(&nr_dentry_unused, 0); |
| 2432 | + |
| 2420 | 2433 | /* |
| 2421 | 2434 | * A constructor could be added for stable state like the lists, |
| 2422 | 2435 | * but it is probably not worth it because of the cache nature |