diff options
Diffstat (limited to 'fs/inode.c')
-rw-r--r-- | fs/inode.c | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/fs/inode.c b/fs/inode.c index ae2727ab0c3a..da85e56378f3 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -102,26 +102,29 @@ static DECLARE_RWSEM(iprune_sem); | |||
102 | */ | 102 | */ |
103 | struct inodes_stat_t inodes_stat; | 103 | struct inodes_stat_t inodes_stat; |
104 | 104 | ||
105 | static struct percpu_counter nr_inodes __cacheline_aligned_in_smp; | 105 | static DEFINE_PER_CPU(unsigned int, nr_inodes); |
106 | static struct percpu_counter nr_inodes_unused __cacheline_aligned_in_smp; | ||
107 | 106 | ||
108 | static struct kmem_cache *inode_cachep __read_mostly; | 107 | static struct kmem_cache *inode_cachep __read_mostly; |
109 | 108 | ||
110 | static inline int get_nr_inodes(void) | 109 | static int get_nr_inodes(void) |
111 | { | 110 | { |
112 | return percpu_counter_sum_positive(&nr_inodes); | 111 | int i; |
112 | int sum = 0; | ||
113 | for_each_possible_cpu(i) | ||
114 | sum += per_cpu(nr_inodes, i); | ||
115 | return sum < 0 ? 0 : sum; | ||
113 | } | 116 | } |
114 | 117 | ||
115 | static inline int get_nr_inodes_unused(void) | 118 | static inline int get_nr_inodes_unused(void) |
116 | { | 119 | { |
117 | return percpu_counter_sum_positive(&nr_inodes_unused); | 120 | return inodes_stat.nr_unused; |
118 | } | 121 | } |
119 | 122 | ||
120 | int get_nr_dirty_inodes(void) | 123 | int get_nr_dirty_inodes(void) |
121 | { | 124 | { |
125 | /* not actually dirty inodes, but a wild approximation */ | ||
122 | int nr_dirty = get_nr_inodes() - get_nr_inodes_unused(); | 126 | int nr_dirty = get_nr_inodes() - get_nr_inodes_unused(); |
123 | return nr_dirty > 0 ? nr_dirty : 0; | 127 | return nr_dirty > 0 ? nr_dirty : 0; |
124 | |||
125 | } | 128 | } |
126 | 129 | ||
127 | /* | 130 | /* |
@@ -132,7 +135,6 @@ int proc_nr_inodes(ctl_table *table, int write, | |||
132 | void __user *buffer, size_t *lenp, loff_t *ppos) | 135 | void __user *buffer, size_t *lenp, loff_t *ppos) |
133 | { | 136 | { |
134 | inodes_stat.nr_inodes = get_nr_inodes(); | 137 | inodes_stat.nr_inodes = get_nr_inodes(); |
135 | inodes_stat.nr_unused = get_nr_inodes_unused(); | ||
136 | return proc_dointvec(table, write, buffer, lenp, ppos); | 138 | return proc_dointvec(table, write, buffer, lenp, ppos); |
137 | } | 139 | } |
138 | #endif | 140 | #endif |
@@ -224,7 +226,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
224 | inode->i_fsnotify_mask = 0; | 226 | inode->i_fsnotify_mask = 0; |
225 | #endif | 227 | #endif |
226 | 228 | ||
227 | percpu_counter_inc(&nr_inodes); | 229 | this_cpu_inc(nr_inodes); |
228 | 230 | ||
229 | return 0; | 231 | return 0; |
230 | out: | 232 | out: |
@@ -255,6 +257,12 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
255 | return inode; | 257 | return inode; |
256 | } | 258 | } |
257 | 259 | ||
260 | void free_inode_nonrcu(struct inode *inode) | ||
261 | { | ||
262 | kmem_cache_free(inode_cachep, inode); | ||
263 | } | ||
264 | EXPORT_SYMBOL(free_inode_nonrcu); | ||
265 | |||
258 | void __destroy_inode(struct inode *inode) | 266 | void __destroy_inode(struct inode *inode) |
259 | { | 267 | { |
260 | BUG_ON(inode_has_buffers(inode)); | 268 | BUG_ON(inode_has_buffers(inode)); |
@@ -266,10 +274,17 @@ void __destroy_inode(struct inode *inode) | |||
266 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) | 274 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) |
267 | posix_acl_release(inode->i_default_acl); | 275 | posix_acl_release(inode->i_default_acl); |
268 | #endif | 276 | #endif |
269 | percpu_counter_dec(&nr_inodes); | 277 | this_cpu_dec(nr_inodes); |
270 | } | 278 | } |
271 | EXPORT_SYMBOL(__destroy_inode); | 279 | EXPORT_SYMBOL(__destroy_inode); |
272 | 280 | ||
281 | static void i_callback(struct rcu_head *head) | ||
282 | { | ||
283 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
284 | INIT_LIST_HEAD(&inode->i_dentry); | ||
285 | kmem_cache_free(inode_cachep, inode); | ||
286 | } | ||
287 | |||
273 | static void destroy_inode(struct inode *inode) | 288 | static void destroy_inode(struct inode *inode) |
274 | { | 289 | { |
275 | BUG_ON(!list_empty(&inode->i_lru)); | 290 | BUG_ON(!list_empty(&inode->i_lru)); |
@@ -277,7 +292,7 @@ static void destroy_inode(struct inode *inode) | |||
277 | if (inode->i_sb->s_op->destroy_inode) | 292 | if (inode->i_sb->s_op->destroy_inode) |
278 | inode->i_sb->s_op->destroy_inode(inode); | 293 | inode->i_sb->s_op->destroy_inode(inode); |
279 | else | 294 | else |
280 | kmem_cache_free(inode_cachep, (inode)); | 295 | call_rcu(&inode->i_rcu, i_callback); |
281 | } | 296 | } |
282 | 297 | ||
283 | /* | 298 | /* |
@@ -335,7 +350,7 @@ static void inode_lru_list_add(struct inode *inode) | |||
335 | { | 350 | { |
336 | if (list_empty(&inode->i_lru)) { | 351 | if (list_empty(&inode->i_lru)) { |
337 | list_add(&inode->i_lru, &inode_lru); | 352 | list_add(&inode->i_lru, &inode_lru); |
338 | percpu_counter_inc(&nr_inodes_unused); | 353 | inodes_stat.nr_unused++; |
339 | } | 354 | } |
340 | } | 355 | } |
341 | 356 | ||
@@ -343,7 +358,7 @@ static void inode_lru_list_del(struct inode *inode) | |||
343 | { | 358 | { |
344 | if (!list_empty(&inode->i_lru)) { | 359 | if (!list_empty(&inode->i_lru)) { |
345 | list_del_init(&inode->i_lru); | 360 | list_del_init(&inode->i_lru); |
346 | percpu_counter_dec(&nr_inodes_unused); | 361 | inodes_stat.nr_unused--; |
347 | } | 362 | } |
348 | } | 363 | } |
349 | 364 | ||
@@ -430,6 +445,7 @@ void end_writeback(struct inode *inode) | |||
430 | BUG_ON(!(inode->i_state & I_FREEING)); | 445 | BUG_ON(!(inode->i_state & I_FREEING)); |
431 | BUG_ON(inode->i_state & I_CLEAR); | 446 | BUG_ON(inode->i_state & I_CLEAR); |
432 | inode_sync_wait(inode); | 447 | inode_sync_wait(inode); |
448 | /* don't need i_lock here, no concurrent mods to i_state */ | ||
433 | inode->i_state = I_FREEING | I_CLEAR; | 449 | inode->i_state = I_FREEING | I_CLEAR; |
434 | } | 450 | } |
435 | EXPORT_SYMBOL(end_writeback); | 451 | EXPORT_SYMBOL(end_writeback); |
@@ -513,7 +529,7 @@ void evict_inodes(struct super_block *sb) | |||
513 | list_move(&inode->i_lru, &dispose); | 529 | list_move(&inode->i_lru, &dispose); |
514 | list_del_init(&inode->i_wb_list); | 530 | list_del_init(&inode->i_wb_list); |
515 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) | 531 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) |
516 | percpu_counter_dec(&nr_inodes_unused); | 532 | inodes_stat.nr_unused--; |
517 | } | 533 | } |
518 | spin_unlock(&inode_lock); | 534 | spin_unlock(&inode_lock); |
519 | 535 | ||
@@ -554,7 +570,7 @@ int invalidate_inodes(struct super_block *sb) | |||
554 | list_move(&inode->i_lru, &dispose); | 570 | list_move(&inode->i_lru, &dispose); |
555 | list_del_init(&inode->i_wb_list); | 571 | list_del_init(&inode->i_wb_list); |
556 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) | 572 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) |
557 | percpu_counter_dec(&nr_inodes_unused); | 573 | inodes_stat.nr_unused--; |
558 | } | 574 | } |
559 | spin_unlock(&inode_lock); | 575 | spin_unlock(&inode_lock); |
560 | 576 | ||
@@ -616,7 +632,7 @@ static void prune_icache(int nr_to_scan) | |||
616 | if (atomic_read(&inode->i_count) || | 632 | if (atomic_read(&inode->i_count) || |
617 | (inode->i_state & ~I_REFERENCED)) { | 633 | (inode->i_state & ~I_REFERENCED)) { |
618 | list_del_init(&inode->i_lru); | 634 | list_del_init(&inode->i_lru); |
619 | percpu_counter_dec(&nr_inodes_unused); | 635 | inodes_stat.nr_unused--; |
620 | continue; | 636 | continue; |
621 | } | 637 | } |
622 | 638 | ||
@@ -650,7 +666,7 @@ static void prune_icache(int nr_to_scan) | |||
650 | */ | 666 | */ |
651 | list_move(&inode->i_lru, &freeable); | 667 | list_move(&inode->i_lru, &freeable); |
652 | list_del_init(&inode->i_wb_list); | 668 | list_del_init(&inode->i_wb_list); |
653 | percpu_counter_dec(&nr_inodes_unused); | 669 | inodes_stat.nr_unused--; |
654 | } | 670 | } |
655 | if (current_is_kswapd()) | 671 | if (current_is_kswapd()) |
656 | __count_vm_events(KSWAPD_INODESTEAL, reap); | 672 | __count_vm_events(KSWAPD_INODESTEAL, reap); |
@@ -1648,8 +1664,6 @@ void __init inode_init(void) | |||
1648 | SLAB_MEM_SPREAD), | 1664 | SLAB_MEM_SPREAD), |
1649 | init_once); | 1665 | init_once); |
1650 | register_shrinker(&icache_shrinker); | 1666 | register_shrinker(&icache_shrinker); |
1651 | percpu_counter_init(&nr_inodes, 0); | ||
1652 | percpu_counter_init(&nr_inodes_unused, 0); | ||
1653 | 1667 | ||
1654 | /* Hash may have been set up in inode_init_early */ | 1668 | /* Hash may have been set up in inode_init_early */ |
1655 | if (!hashdist) | 1669 | if (!hashdist) |