diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 2593153471cf..aac41adf4743 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -119,6 +119,7 @@ struct dentry_stat_t dentry_stat = { | |||
119 | 119 | ||
120 | static DEFINE_PER_CPU(long, nr_dentry); | 120 | static DEFINE_PER_CPU(long, nr_dentry); |
121 | static DEFINE_PER_CPU(long, nr_dentry_unused); | 121 | static DEFINE_PER_CPU(long, nr_dentry_unused); |
122 | static DEFINE_PER_CPU(long, nr_dentry_negative); | ||
122 | 123 | ||
123 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) | 124 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) |
124 | 125 | ||
@@ -152,11 +153,22 @@ static long get_nr_dentry_unused(void) | |||
152 | return sum < 0 ? 0 : sum; | 153 | return sum < 0 ? 0 : sum; |
153 | } | 154 | } |
154 | 155 | ||
156 | static long get_nr_dentry_negative(void) | ||
157 | { | ||
158 | int i; | ||
159 | long sum = 0; | ||
160 | |||
161 | for_each_possible_cpu(i) | ||
162 | sum += per_cpu(nr_dentry_negative, i); | ||
163 | return sum < 0 ? 0 : sum; | ||
164 | } | ||
165 | |||
155 | int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, | 166 | int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, |
156 | size_t *lenp, loff_t *ppos) | 167 | size_t *lenp, loff_t *ppos) |
157 | { | 168 | { |
158 | dentry_stat.nr_dentry = get_nr_dentry(); | 169 | dentry_stat.nr_dentry = get_nr_dentry(); |
159 | dentry_stat.nr_unused = get_nr_dentry_unused(); | 170 | dentry_stat.nr_unused = get_nr_dentry_unused(); |
171 | dentry_stat.nr_negative = get_nr_dentry_negative(); | ||
160 | return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); | 172 | return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); |
161 | } | 173 | } |
162 | #endif | 174 | #endif |
@@ -317,6 +329,8 @@ static inline void __d_clear_type_and_inode(struct dentry *dentry) | |||
317 | flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); | 329 | flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); |
318 | WRITE_ONCE(dentry->d_flags, flags); | 330 | WRITE_ONCE(dentry->d_flags, flags); |
319 | dentry->d_inode = NULL; | 331 | dentry->d_inode = NULL; |
332 | if (dentry->d_flags & DCACHE_LRU_LIST) | ||
333 | this_cpu_inc(nr_dentry_negative); | ||
320 | } | 334 | } |
321 | 335 | ||
322 | static void dentry_free(struct dentry *dentry) | 336 | static void dentry_free(struct dentry *dentry) |
@@ -371,6 +385,11 @@ static void dentry_unlink_inode(struct dentry * dentry) | |||
371 | * The per-cpu "nr_dentry_unused" counters are updated with | 385 | * The per-cpu "nr_dentry_unused" counters are updated with |
372 | * the DCACHE_LRU_LIST bit. | 386 | * the DCACHE_LRU_LIST bit. |
373 | * | 387 | * |
388 | * The per-cpu "nr_dentry_negative" counters are only updated | ||
389 | * when deleted from or added to the per-superblock LRU list, not | ||
390 | * from/to the shrink list. That is to avoid an unneeded dec/inc | ||
391 | * pair when moving from LRU to shrink list in select_collect(). | ||
392 | * | ||
374 | * These helper functions make sure we always follow the | 393 | * These helper functions make sure we always follow the |
375 | * rules. d_lock must be held by the caller. | 394 | * rules. d_lock must be held by the caller. |
376 | */ | 395 | */ |
@@ -380,6 +399,8 @@ static void d_lru_add(struct dentry *dentry) | |||
380 | D_FLAG_VERIFY(dentry, 0); | 399 | D_FLAG_VERIFY(dentry, 0); |
381 | dentry->d_flags |= DCACHE_LRU_LIST; | 400 | dentry->d_flags |= DCACHE_LRU_LIST; |
382 | this_cpu_inc(nr_dentry_unused); | 401 | this_cpu_inc(nr_dentry_unused); |
402 | if (d_is_negative(dentry)) | ||
403 | this_cpu_inc(nr_dentry_negative); | ||
383 | WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); | 404 | WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); |
384 | } | 405 | } |
385 | 406 | ||
@@ -388,6 +409,8 @@ static void d_lru_del(struct dentry *dentry) | |||
388 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); | 409 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); |
389 | dentry->d_flags &= ~DCACHE_LRU_LIST; | 410 | dentry->d_flags &= ~DCACHE_LRU_LIST; |
390 | this_cpu_dec(nr_dentry_unused); | 411 | this_cpu_dec(nr_dentry_unused); |
412 | if (d_is_negative(dentry)) | ||
413 | this_cpu_dec(nr_dentry_negative); | ||
391 | WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); | 414 | WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); |
392 | } | 415 | } |
393 | 416 | ||
@@ -418,6 +441,8 @@ static void d_lru_isolate(struct list_lru_one *lru, struct dentry *dentry) | |||
418 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); | 441 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); |
419 | dentry->d_flags &= ~DCACHE_LRU_LIST; | 442 | dentry->d_flags &= ~DCACHE_LRU_LIST; |
420 | this_cpu_dec(nr_dentry_unused); | 443 | this_cpu_dec(nr_dentry_unused); |
444 | if (d_is_negative(dentry)) | ||
445 | this_cpu_dec(nr_dentry_negative); | ||
421 | list_lru_isolate(lru, &dentry->d_lru); | 446 | list_lru_isolate(lru, &dentry->d_lru); |
422 | } | 447 | } |
423 | 448 | ||
@@ -426,6 +451,8 @@ static void d_lru_shrink_move(struct list_lru_one *lru, struct dentry *dentry, | |||
426 | { | 451 | { |
427 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); | 452 | D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); |
428 | dentry->d_flags |= DCACHE_SHRINK_LIST; | 453 | dentry->d_flags |= DCACHE_SHRINK_LIST; |
454 | if (d_is_negative(dentry)) | ||
455 | this_cpu_dec(nr_dentry_negative); | ||
429 | list_lru_isolate_move(lru, &dentry->d_lru, list); | 456 | list_lru_isolate_move(lru, &dentry->d_lru, list); |
430 | } | 457 | } |
431 | 458 | ||
@@ -1188,15 +1215,11 @@ static enum lru_status dentry_lru_isolate_shrink(struct list_head *item, | |||
1188 | */ | 1215 | */ |
1189 | void shrink_dcache_sb(struct super_block *sb) | 1216 | void shrink_dcache_sb(struct super_block *sb) |
1190 | { | 1217 | { |
1191 | long freed; | ||
1192 | |||
1193 | do { | 1218 | do { |
1194 | LIST_HEAD(dispose); | 1219 | LIST_HEAD(dispose); |
1195 | 1220 | ||
1196 | freed = list_lru_walk(&sb->s_dentry_lru, | 1221 | list_lru_walk(&sb->s_dentry_lru, |
1197 | dentry_lru_isolate_shrink, &dispose, 1024); | 1222 | dentry_lru_isolate_shrink, &dispose, 1024); |
1198 | |||
1199 | this_cpu_sub(nr_dentry_unused, freed); | ||
1200 | shrink_dentry_list(&dispose); | 1223 | shrink_dentry_list(&dispose); |
1201 | } while (list_lru_count(&sb->s_dentry_lru) > 0); | 1224 | } while (list_lru_count(&sb->s_dentry_lru) > 0); |
1202 | } | 1225 | } |
@@ -1820,6 +1843,11 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) | |||
1820 | WARN_ON(d_in_lookup(dentry)); | 1843 | WARN_ON(d_in_lookup(dentry)); |
1821 | 1844 | ||
1822 | spin_lock(&dentry->d_lock); | 1845 | spin_lock(&dentry->d_lock); |
1846 | /* | ||
1847 | * Decrement negative dentry count if it was in the LRU list. | ||
1848 | */ | ||
1849 | if (dentry->d_flags & DCACHE_LRU_LIST) | ||
1850 | this_cpu_dec(nr_dentry_negative); | ||
1823 | hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); | 1851 | hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); |
1824 | raw_write_seqcount_begin(&dentry->d_seq); | 1852 | raw_write_seqcount_begin(&dentry->d_seq); |
1825 | __d_set_inode_and_type(dentry, inode, add_flags); | 1853 | __d_set_inode_and_type(dentry, inode, add_flags); |