diff options
author | Konstantin Khlebnikov <khlebnikov@yandex-team.ru> | 2015-02-19 12:19:35 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-02-22 11:38:42 -0500 |
commit | eb6ef3df4faa5424cf2a24b4e4f3eeceb1482a8e (patch) | |
tree | 760db5df872be2122597841c33479c41cf2d7194 /fs/fs-writeback.c | |
parent | 54f2a2f42759b11ada761013a12f0e743702219a (diff) |
trylock_super(): replacement for grab_super_passive()
I've noticed significant locking contention in memory reclaimer around
sb_lock inside grab_super_passive(). Grab_super_passive() is called from
two places: in icache/dcache shrinkers (function super_cache_scan) and
from writeback (function __writeback_inodes_wb). Both are required for
progress in memory allocator.
Grab_super_passive() acquires sb_lock to increment sb->s_count and check
sb->s_instances. It seems sb->s_umount locked for read is enough here:
super-block deactivation always runs under sb->s_umount locked for write.
Protecting super-block itself isn't a problem: in super_cache_scan() sb
is protected by shrinker_rwsem: it cannot be freed if its slab shrinkers
are still active. Inside writeback super-block comes from inode from bdi
writeback list under wb->list_lock.
This patch removes locking sb_lock and checks s_instances under s_umount:
generic_shutdown_super() unlinks it under sb->s_umount locked for write.
New variant is called trylock_super() and since it only locks semaphore,
callers must call up_read(&sb->s_umount) instead of drop_super(sb) when
they're done.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 073657f755d4..e907052eeadb 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -769,9 +769,9 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb, | |||
769 | struct inode *inode = wb_inode(wb->b_io.prev); | 769 | struct inode *inode = wb_inode(wb->b_io.prev); |
770 | struct super_block *sb = inode->i_sb; | 770 | struct super_block *sb = inode->i_sb; |
771 | 771 | ||
772 | if (!grab_super_passive(sb)) { | 772 | if (!trylock_super(sb)) { |
773 | /* | 773 | /* |
774 | * grab_super_passive() may fail consistently due to | 774 | * trylock_super() may fail consistently due to |
775 | * s_umount being grabbed by someone else. Don't use | 775 | * s_umount being grabbed by someone else. Don't use |
776 | * requeue_io() to avoid busy retrying the inode/sb. | 776 | * requeue_io() to avoid busy retrying the inode/sb. |
777 | */ | 777 | */ |
@@ -779,7 +779,7 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb, | |||
779 | continue; | 779 | continue; |
780 | } | 780 | } |
781 | wrote += writeback_sb_inodes(sb, wb, work); | 781 | wrote += writeback_sb_inodes(sb, wb, work); |
782 | drop_super(sb); | 782 | up_read(&sb->s_umount); |
783 | 783 | ||
784 | /* refer to the same tests at the end of writeback_sb_inodes */ | 784 | /* refer to the same tests at the end of writeback_sb_inodes */ |
785 | if (wrote) { | 785 | if (wrote) { |