diff options
author | Dave Chinner <dchinner@redhat.com> | 2015-03-04 12:37:22 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fb.com> | 2015-08-17 18:39:46 -0400 |
commit | 74278da9f70d84d715601fe794567a6d2bfdf078 (patch) | |
tree | 49262a88fc42b85bfe4930f5cd7a832d5ba647c6 | |
parent | cbedaac63481dea52327127a9f1c60f092bd6b07 (diff) |
inode: convert inode_sb_list_lock to per-sb
The process of reducing contention on per-superblock inode lists
starts with moving the locking to match the per-superblock inode
list. This takes the global lock out of the picture and reduces the
contention problems to within a single filesystem. This doesn't get
rid of contention as the locks still have global CPU scope, but it
does isolate operations on different superblocks form each other.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Dave Chinner <dchinner@redhat.com>
-rw-r--r-- | fs/block_dev.c | 12 | ||||
-rw-r--r-- | fs/drop_caches.c | 10 | ||||
-rw-r--r-- | fs/fs-writeback.c | 12 | ||||
-rw-r--r-- | fs/inode.c | 28 | ||||
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/notify/inode_mark.c | 20 | ||||
-rw-r--r-- | fs/quota/dquot.c | 16 | ||||
-rw-r--r-- | fs/super.c | 3 | ||||
-rw-r--r-- | include/linux/fs.h | 5 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 4 |
10 files changed, 57 insertions, 54 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 198243717da5..33b813e04f79 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1769,7 +1769,7 @@ void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg) | |||
1769 | { | 1769 | { |
1770 | struct inode *inode, *old_inode = NULL; | 1770 | struct inode *inode, *old_inode = NULL; |
1771 | 1771 | ||
1772 | spin_lock(&inode_sb_list_lock); | 1772 | spin_lock(&blockdev_superblock->s_inode_list_lock); |
1773 | list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) { | 1773 | list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) { |
1774 | struct address_space *mapping = inode->i_mapping; | 1774 | struct address_space *mapping = inode->i_mapping; |
1775 | 1775 | ||
@@ -1781,13 +1781,13 @@ void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg) | |||
1781 | } | 1781 | } |
1782 | __iget(inode); | 1782 | __iget(inode); |
1783 | spin_unlock(&inode->i_lock); | 1783 | spin_unlock(&inode->i_lock); |
1784 | spin_unlock(&inode_sb_list_lock); | 1784 | spin_unlock(&blockdev_superblock->s_inode_list_lock); |
1785 | /* | 1785 | /* |
1786 | * We hold a reference to 'inode' so it couldn't have been | 1786 | * We hold a reference to 'inode' so it couldn't have been |
1787 | * removed from s_inodes list while we dropped the | 1787 | * removed from s_inodes list while we dropped the |
1788 | * inode_sb_list_lock. We cannot iput the inode now as we can | 1788 | * s_inode_list_lock We cannot iput the inode now as we can |
1789 | * be holding the last reference and we cannot iput it under | 1789 | * be holding the last reference and we cannot iput it under |
1790 | * inode_sb_list_lock. So we keep the reference and iput it | 1790 | * s_inode_list_lock. So we keep the reference and iput it |
1791 | * later. | 1791 | * later. |
1792 | */ | 1792 | */ |
1793 | iput(old_inode); | 1793 | iput(old_inode); |
@@ -1795,8 +1795,8 @@ void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg) | |||
1795 | 1795 | ||
1796 | func(I_BDEV(inode), arg); | 1796 | func(I_BDEV(inode), arg); |
1797 | 1797 | ||
1798 | spin_lock(&inode_sb_list_lock); | 1798 | spin_lock(&blockdev_superblock->s_inode_list_lock); |
1799 | } | 1799 | } |
1800 | spin_unlock(&inode_sb_list_lock); | 1800 | spin_unlock(&blockdev_superblock->s_inode_list_lock); |
1801 | iput(old_inode); | 1801 | iput(old_inode); |
1802 | } | 1802 | } |
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 5718cb9f7273..d72d52b90433 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c | |||
@@ -17,7 +17,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
17 | { | 17 | { |
18 | struct inode *inode, *toput_inode = NULL; | 18 | struct inode *inode, *toput_inode = NULL; |
19 | 19 | ||
20 | spin_lock(&inode_sb_list_lock); | 20 | spin_lock(&sb->s_inode_list_lock); |
21 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 21 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
22 | spin_lock(&inode->i_lock); | 22 | spin_lock(&inode->i_lock); |
23 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || | 23 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || |
@@ -27,13 +27,15 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
27 | } | 27 | } |
28 | __iget(inode); | 28 | __iget(inode); |
29 | spin_unlock(&inode->i_lock); | 29 | spin_unlock(&inode->i_lock); |
30 | spin_unlock(&inode_sb_list_lock); | 30 | spin_unlock(&sb->s_inode_list_lock); |
31 | |||
31 | invalidate_mapping_pages(inode->i_mapping, 0, -1); | 32 | invalidate_mapping_pages(inode->i_mapping, 0, -1); |
32 | iput(toput_inode); | 33 | iput(toput_inode); |
33 | toput_inode = inode; | 34 | toput_inode = inode; |
34 | spin_lock(&inode_sb_list_lock); | 35 | |
36 | spin_lock(&sb->s_inode_list_lock); | ||
35 | } | 37 | } |
36 | spin_unlock(&inode_sb_list_lock); | 38 | spin_unlock(&sb->s_inode_list_lock); |
37 | iput(toput_inode); | 39 | iput(toput_inode); |
38 | } | 40 | } |
39 | 41 | ||
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index d98e37bbf417..f45bf876579f 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -2124,7 +2124,7 @@ static void wait_sb_inodes(struct super_block *sb) | |||
2124 | */ | 2124 | */ |
2125 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 2125 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
2126 | 2126 | ||
2127 | spin_lock(&inode_sb_list_lock); | 2127 | spin_lock(&sb->s_inode_list_lock); |
2128 | 2128 | ||
2129 | /* | 2129 | /* |
2130 | * Data integrity sync. Must wait for all pages under writeback, | 2130 | * Data integrity sync. Must wait for all pages under writeback, |
@@ -2144,14 +2144,14 @@ static void wait_sb_inodes(struct super_block *sb) | |||
2144 | } | 2144 | } |
2145 | __iget(inode); | 2145 | __iget(inode); |
2146 | spin_unlock(&inode->i_lock); | 2146 | spin_unlock(&inode->i_lock); |
2147 | spin_unlock(&inode_sb_list_lock); | 2147 | spin_unlock(&sb->s_inode_list_lock); |
2148 | 2148 | ||
2149 | /* | 2149 | /* |
2150 | * We hold a reference to 'inode' so it couldn't have been | 2150 | * We hold a reference to 'inode' so it couldn't have been |
2151 | * removed from s_inodes list while we dropped the | 2151 | * removed from s_inodes list while we dropped the |
2152 | * inode_sb_list_lock. We cannot iput the inode now as we can | 2152 | * s_inode_list_lock. We cannot iput the inode now as we can |
2153 | * be holding the last reference and we cannot iput it under | 2153 | * be holding the last reference and we cannot iput it under |
2154 | * inode_sb_list_lock. So we keep the reference and iput it | 2154 | * s_inode_list_lock. So we keep the reference and iput it |
2155 | * later. | 2155 | * later. |
2156 | */ | 2156 | */ |
2157 | iput(old_inode); | 2157 | iput(old_inode); |
@@ -2161,9 +2161,9 @@ static void wait_sb_inodes(struct super_block *sb) | |||
2161 | 2161 | ||
2162 | cond_resched(); | 2162 | cond_resched(); |
2163 | 2163 | ||
2164 | spin_lock(&inode_sb_list_lock); | 2164 | spin_lock(&sb->s_inode_list_lock); |
2165 | } | 2165 | } |
2166 | spin_unlock(&inode_sb_list_lock); | 2166 | spin_unlock(&sb->s_inode_list_lock); |
2167 | iput(old_inode); | 2167 | iput(old_inode); |
2168 | } | 2168 | } |
2169 | 2169 | ||
diff --git a/fs/inode.c b/fs/inode.c index d30640f7a193..a2de294f6b77 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -28,8 +28,8 @@ | |||
28 | * inode->i_state, inode->i_hash, __iget() | 28 | * inode->i_state, inode->i_hash, __iget() |
29 | * Inode LRU list locks protect: | 29 | * Inode LRU list locks protect: |
30 | * inode->i_sb->s_inode_lru, inode->i_lru | 30 | * inode->i_sb->s_inode_lru, inode->i_lru |
31 | * inode_sb_list_lock protects: | 31 | * inode->i_sb->s_inode_list_lock protects: |
32 | * sb->s_inodes, inode->i_sb_list | 32 | * inode->i_sb->s_inodes, inode->i_sb_list |
33 | * bdi->wb.list_lock protects: | 33 | * bdi->wb.list_lock protects: |
34 | * bdi->wb.b_{dirty,io,more_io,dirty_time}, inode->i_wb_list | 34 | * bdi->wb.b_{dirty,io,more_io,dirty_time}, inode->i_wb_list |
35 | * inode_hash_lock protects: | 35 | * inode_hash_lock protects: |
@@ -37,7 +37,7 @@ | |||
37 | * | 37 | * |
38 | * Lock ordering: | 38 | * Lock ordering: |
39 | * | 39 | * |
40 | * inode_sb_list_lock | 40 | * inode->i_sb->s_inode_list_lock |
41 | * inode->i_lock | 41 | * inode->i_lock |
42 | * Inode LRU list locks | 42 | * Inode LRU list locks |
43 | * | 43 | * |
@@ -45,7 +45,7 @@ | |||
45 | * inode->i_lock | 45 | * inode->i_lock |
46 | * | 46 | * |
47 | * inode_hash_lock | 47 | * inode_hash_lock |
48 | * inode_sb_list_lock | 48 | * inode->i_sb->s_inode_list_lock |
49 | * inode->i_lock | 49 | * inode->i_lock |
50 | * | 50 | * |
51 | * iunique_lock | 51 | * iunique_lock |
@@ -57,8 +57,6 @@ static unsigned int i_hash_shift __read_mostly; | |||
57 | static struct hlist_head *inode_hashtable __read_mostly; | 57 | static struct hlist_head *inode_hashtable __read_mostly; |
58 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); | 58 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); |
59 | 59 | ||
60 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); | ||
61 | |||
62 | /* | 60 | /* |
63 | * Empty aops. Can be used for the cases where the user does not | 61 | * Empty aops. Can be used for the cases where the user does not |
64 | * define any of the address_space operations. | 62 | * define any of the address_space operations. |
@@ -426,18 +424,18 @@ static void inode_lru_list_del(struct inode *inode) | |||
426 | */ | 424 | */ |
427 | void inode_sb_list_add(struct inode *inode) | 425 | void inode_sb_list_add(struct inode *inode) |
428 | { | 426 | { |
429 | spin_lock(&inode_sb_list_lock); | 427 | spin_lock(&inode->i_sb->s_inode_list_lock); |
430 | list_add(&inode->i_sb_list, &inode->i_sb->s_inodes); | 428 | list_add(&inode->i_sb_list, &inode->i_sb->s_inodes); |
431 | spin_unlock(&inode_sb_list_lock); | 429 | spin_unlock(&inode->i_sb->s_inode_list_lock); |
432 | } | 430 | } |
433 | EXPORT_SYMBOL_GPL(inode_sb_list_add); | 431 | EXPORT_SYMBOL_GPL(inode_sb_list_add); |
434 | 432 | ||
435 | static inline void inode_sb_list_del(struct inode *inode) | 433 | static inline void inode_sb_list_del(struct inode *inode) |
436 | { | 434 | { |
437 | if (!list_empty(&inode->i_sb_list)) { | 435 | if (!list_empty(&inode->i_sb_list)) { |
438 | spin_lock(&inode_sb_list_lock); | 436 | spin_lock(&inode->i_sb->s_inode_list_lock); |
439 | list_del_init(&inode->i_sb_list); | 437 | list_del_init(&inode->i_sb_list); |
440 | spin_unlock(&inode_sb_list_lock); | 438 | spin_unlock(&inode->i_sb->s_inode_list_lock); |
441 | } | 439 | } |
442 | } | 440 | } |
443 | 441 | ||
@@ -594,7 +592,7 @@ void evict_inodes(struct super_block *sb) | |||
594 | struct inode *inode, *next; | 592 | struct inode *inode, *next; |
595 | LIST_HEAD(dispose); | 593 | LIST_HEAD(dispose); |
596 | 594 | ||
597 | spin_lock(&inode_sb_list_lock); | 595 | spin_lock(&sb->s_inode_list_lock); |
598 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 596 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { |
599 | if (atomic_read(&inode->i_count)) | 597 | if (atomic_read(&inode->i_count)) |
600 | continue; | 598 | continue; |
@@ -610,7 +608,7 @@ void evict_inodes(struct super_block *sb) | |||
610 | spin_unlock(&inode->i_lock); | 608 | spin_unlock(&inode->i_lock); |
611 | list_add(&inode->i_lru, &dispose); | 609 | list_add(&inode->i_lru, &dispose); |
612 | } | 610 | } |
613 | spin_unlock(&inode_sb_list_lock); | 611 | spin_unlock(&sb->s_inode_list_lock); |
614 | 612 | ||
615 | dispose_list(&dispose); | 613 | dispose_list(&dispose); |
616 | } | 614 | } |
@@ -631,7 +629,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) | |||
631 | struct inode *inode, *next; | 629 | struct inode *inode, *next; |
632 | LIST_HEAD(dispose); | 630 | LIST_HEAD(dispose); |
633 | 631 | ||
634 | spin_lock(&inode_sb_list_lock); | 632 | spin_lock(&sb->s_inode_list_lock); |
635 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 633 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { |
636 | spin_lock(&inode->i_lock); | 634 | spin_lock(&inode->i_lock); |
637 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { | 635 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { |
@@ -654,7 +652,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) | |||
654 | spin_unlock(&inode->i_lock); | 652 | spin_unlock(&inode->i_lock); |
655 | list_add(&inode->i_lru, &dispose); | 653 | list_add(&inode->i_lru, &dispose); |
656 | } | 654 | } |
657 | spin_unlock(&inode_sb_list_lock); | 655 | spin_unlock(&sb->s_inode_list_lock); |
658 | 656 | ||
659 | dispose_list(&dispose); | 657 | dispose_list(&dispose); |
660 | 658 | ||
@@ -890,7 +888,7 @@ struct inode *new_inode(struct super_block *sb) | |||
890 | { | 888 | { |
891 | struct inode *inode; | 889 | struct inode *inode; |
892 | 890 | ||
893 | spin_lock_prefetch(&inode_sb_list_lock); | 891 | spin_lock_prefetch(&sb->s_inode_list_lock); |
894 | 892 | ||
895 | inode = new_inode_pseudo(sb); | 893 | inode = new_inode_pseudo(sb); |
896 | if (inode) | 894 | if (inode) |
diff --git a/fs/internal.h b/fs/internal.h index 4d5af583ab03..ee1209c54eb1 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -112,7 +112,6 @@ extern int vfs_open(const struct path *, struct file *, const struct cred *); | |||
112 | /* | 112 | /* |
113 | * inode.c | 113 | * inode.c |
114 | */ | 114 | */ |
115 | extern spinlock_t inode_sb_list_lock; | ||
116 | extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc); | 115 | extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc); |
117 | extern void inode_add_lru(struct inode *inode); | 116 | extern void inode_add_lru(struct inode *inode); |
118 | 117 | ||
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 3daf513ee99e..a4e1a8f6c329 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -163,17 +163,17 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
163 | 163 | ||
164 | /** | 164 | /** |
165 | * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. | 165 | * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. |
166 | * @list: list of inodes being unmounted (sb->s_inodes) | 166 | * @sb: superblock being unmounted. |
167 | * | 167 | * |
168 | * Called during unmount with no locks held, so needs to be safe against | 168 | * Called during unmount with no locks held, so needs to be safe against |
169 | * concurrent modifiers. We temporarily drop inode_sb_list_lock and CAN block. | 169 | * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. |
170 | */ | 170 | */ |
171 | void fsnotify_unmount_inodes(struct list_head *list) | 171 | void fsnotify_unmount_inodes(struct super_block *sb) |
172 | { | 172 | { |
173 | struct inode *inode, *next_i, *need_iput = NULL; | 173 | struct inode *inode, *next_i, *need_iput = NULL; |
174 | 174 | ||
175 | spin_lock(&inode_sb_list_lock); | 175 | spin_lock(&sb->s_inode_list_lock); |
176 | list_for_each_entry_safe(inode, next_i, list, i_sb_list) { | 176 | list_for_each_entry_safe(inode, next_i, &sb->s_inodes, i_sb_list) { |
177 | struct inode *need_iput_tmp; | 177 | struct inode *need_iput_tmp; |
178 | 178 | ||
179 | /* | 179 | /* |
@@ -209,7 +209,7 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
209 | spin_unlock(&inode->i_lock); | 209 | spin_unlock(&inode->i_lock); |
210 | 210 | ||
211 | /* In case the dropping of a reference would nuke next_i. */ | 211 | /* In case the dropping of a reference would nuke next_i. */ |
212 | while (&next_i->i_sb_list != list) { | 212 | while (&next_i->i_sb_list != &sb->s_inodes) { |
213 | spin_lock(&next_i->i_lock); | 213 | spin_lock(&next_i->i_lock); |
214 | if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) && | 214 | if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) && |
215 | atomic_read(&next_i->i_count)) { | 215 | atomic_read(&next_i->i_count)) { |
@@ -224,12 +224,12 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
224 | } | 224 | } |
225 | 225 | ||
226 | /* | 226 | /* |
227 | * We can safely drop inode_sb_list_lock here because either | 227 | * We can safely drop s_inode_list_lock here because either |
228 | * we actually hold references on both inode and next_i or | 228 | * we actually hold references on both inode and next_i or |
229 | * end of list. Also no new inodes will be added since the | 229 | * end of list. Also no new inodes will be added since the |
230 | * umount has begun. | 230 | * umount has begun. |
231 | */ | 231 | */ |
232 | spin_unlock(&inode_sb_list_lock); | 232 | spin_unlock(&sb->s_inode_list_lock); |
233 | 233 | ||
234 | if (need_iput_tmp) | 234 | if (need_iput_tmp) |
235 | iput(need_iput_tmp); | 235 | iput(need_iput_tmp); |
@@ -241,7 +241,7 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
241 | 241 | ||
242 | iput(inode); | 242 | iput(inode); |
243 | 243 | ||
244 | spin_lock(&inode_sb_list_lock); | 244 | spin_lock(&sb->s_inode_list_lock); |
245 | } | 245 | } |
246 | spin_unlock(&inode_sb_list_lock); | 246 | spin_unlock(&sb->s_inode_list_lock); |
247 | } | 247 | } |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 20d1f74561cf..2863ec6cbadf 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -923,7 +923,7 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
923 | int reserved = 0; | 923 | int reserved = 0; |
924 | #endif | 924 | #endif |
925 | 925 | ||
926 | spin_lock(&inode_sb_list_lock); | 926 | spin_lock(&sb->s_inode_list_lock); |
927 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 927 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
928 | spin_lock(&inode->i_lock); | 928 | spin_lock(&inode->i_lock); |
929 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || | 929 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || |
@@ -934,7 +934,7 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
934 | } | 934 | } |
935 | __iget(inode); | 935 | __iget(inode); |
936 | spin_unlock(&inode->i_lock); | 936 | spin_unlock(&inode->i_lock); |
937 | spin_unlock(&inode_sb_list_lock); | 937 | spin_unlock(&sb->s_inode_list_lock); |
938 | 938 | ||
939 | #ifdef CONFIG_QUOTA_DEBUG | 939 | #ifdef CONFIG_QUOTA_DEBUG |
940 | if (unlikely(inode_get_rsv_space(inode) > 0)) | 940 | if (unlikely(inode_get_rsv_space(inode) > 0)) |
@@ -946,15 +946,15 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
946 | /* | 946 | /* |
947 | * We hold a reference to 'inode' so it couldn't have been | 947 | * We hold a reference to 'inode' so it couldn't have been |
948 | * removed from s_inodes list while we dropped the | 948 | * removed from s_inodes list while we dropped the |
949 | * inode_sb_list_lock We cannot iput the inode now as we can be | 949 | * s_inode_list_lock. We cannot iput the inode now as we can be |
950 | * holding the last reference and we cannot iput it under | 950 | * holding the last reference and we cannot iput it under |
951 | * inode_sb_list_lock. So we keep the reference and iput it | 951 | * s_inode_list_lock. So we keep the reference and iput it |
952 | * later. | 952 | * later. |
953 | */ | 953 | */ |
954 | old_inode = inode; | 954 | old_inode = inode; |
955 | spin_lock(&inode_sb_list_lock); | 955 | spin_lock(&sb->s_inode_list_lock); |
956 | } | 956 | } |
957 | spin_unlock(&inode_sb_list_lock); | 957 | spin_unlock(&sb->s_inode_list_lock); |
958 | iput(old_inode); | 958 | iput(old_inode); |
959 | 959 | ||
960 | #ifdef CONFIG_QUOTA_DEBUG | 960 | #ifdef CONFIG_QUOTA_DEBUG |
@@ -1023,7 +1023,7 @@ static void remove_dquot_ref(struct super_block *sb, int type, | |||
1023 | struct inode *inode; | 1023 | struct inode *inode; |
1024 | int reserved = 0; | 1024 | int reserved = 0; |
1025 | 1025 | ||
1026 | spin_lock(&inode_sb_list_lock); | 1026 | spin_lock(&sb->s_inode_list_lock); |
1027 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 1027 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
1028 | /* | 1028 | /* |
1029 | * We have to scan also I_NEW inodes because they can already | 1029 | * We have to scan also I_NEW inodes because they can already |
@@ -1039,7 +1039,7 @@ static void remove_dquot_ref(struct super_block *sb, int type, | |||
1039 | } | 1039 | } |
1040 | spin_unlock(&dq_data_lock); | 1040 | spin_unlock(&dq_data_lock); |
1041 | } | 1041 | } |
1042 | spin_unlock(&inode_sb_list_lock); | 1042 | spin_unlock(&sb->s_inode_list_lock); |
1043 | #ifdef CONFIG_QUOTA_DEBUG | 1043 | #ifdef CONFIG_QUOTA_DEBUG |
1044 | if (reserved) { | 1044 | if (reserved) { |
1045 | printk(KERN_WARNING "VFS (%s): Writes happened after quota" | 1045 | printk(KERN_WARNING "VFS (%s): Writes happened after quota" |
diff --git a/fs/super.c b/fs/super.c index b61372354f2b..c808183554a2 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -191,6 +191,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) | |||
191 | INIT_HLIST_NODE(&s->s_instances); | 191 | INIT_HLIST_NODE(&s->s_instances); |
192 | INIT_HLIST_BL_HEAD(&s->s_anon); | 192 | INIT_HLIST_BL_HEAD(&s->s_anon); |
193 | INIT_LIST_HEAD(&s->s_inodes); | 193 | INIT_LIST_HEAD(&s->s_inodes); |
194 | spin_lock_init(&s->s_inode_list_lock); | ||
194 | 195 | ||
195 | if (list_lru_init_memcg(&s->s_dentry_lru)) | 196 | if (list_lru_init_memcg(&s->s_dentry_lru)) |
196 | goto fail; | 197 | goto fail; |
@@ -399,7 +400,7 @@ void generic_shutdown_super(struct super_block *sb) | |||
399 | sync_filesystem(sb); | 400 | sync_filesystem(sb); |
400 | sb->s_flags &= ~MS_ACTIVE; | 401 | sb->s_flags &= ~MS_ACTIVE; |
401 | 402 | ||
402 | fsnotify_unmount_inodes(&sb->s_inodes); | 403 | fsnotify_unmount_inodes(sb); |
403 | 404 | ||
404 | evict_inodes(sb); | 405 | evict_inodes(sb); |
405 | 406 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 4a40fa843040..09bbd38485f9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1309,7 +1309,6 @@ struct super_block { | |||
1309 | #endif | 1309 | #endif |
1310 | const struct xattr_handler **s_xattr; | 1310 | const struct xattr_handler **s_xattr; |
1311 | 1311 | ||
1312 | struct list_head s_inodes; /* all inodes */ | ||
1313 | struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ | 1312 | struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ |
1314 | struct list_head s_mounts; /* list of mounts; _not_ for fs use */ | 1313 | struct list_head s_mounts; /* list of mounts; _not_ for fs use */ |
1315 | struct block_device *s_bdev; | 1314 | struct block_device *s_bdev; |
@@ -1380,6 +1379,10 @@ struct super_block { | |||
1380 | * Indicates how deep in a filesystem stack this SB is | 1379 | * Indicates how deep in a filesystem stack this SB is |
1381 | */ | 1380 | */ |
1382 | int s_stack_depth; | 1381 | int s_stack_depth; |
1382 | |||
1383 | /* s_inode_list_lock protects s_inodes */ | ||
1384 | spinlock_t s_inode_list_lock ____cacheline_aligned_in_smp; | ||
1385 | struct list_head s_inodes; /* all inodes */ | ||
1383 | }; | 1386 | }; |
1384 | 1387 | ||
1385 | extern struct timespec current_fs_time(struct super_block *sb); | 1388 | extern struct timespec current_fs_time(struct super_block *sb); |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 65a517dd32f7..0390ee69c439 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -357,7 +357,7 @@ extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, un | |||
357 | extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group); | 357 | extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group); |
358 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); | 358 | extern void fsnotify_get_mark(struct fsnotify_mark *mark); |
359 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); | 359 | extern void fsnotify_put_mark(struct fsnotify_mark *mark); |
360 | extern void fsnotify_unmount_inodes(struct list_head *list); | 360 | extern void fsnotify_unmount_inodes(struct super_block *sb); |
361 | 361 | ||
362 | /* put here because inotify does some weird stuff when destroying watches */ | 362 | /* put here because inotify does some weird stuff when destroying watches */ |
363 | extern void fsnotify_init_event(struct fsnotify_event *event, | 363 | extern void fsnotify_init_event(struct fsnotify_event *event, |
@@ -393,7 +393,7 @@ static inline u32 fsnotify_get_cookie(void) | |||
393 | return 0; | 393 | return 0; |
394 | } | 394 | } |
395 | 395 | ||
396 | static inline void fsnotify_unmount_inodes(struct list_head *list) | 396 | static inline void fsnotify_unmount_inodes(struct super_block *sb) |
397 | {} | 397 | {} |
398 | 398 | ||
399 | #endif /* CONFIG_FSNOTIFY */ | 399 | #endif /* CONFIG_FSNOTIFY */ |