aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-01-10 00:47:57 -0500
committerFengguang Wu <fengguang.wu@intel.com>2013-01-11 21:47:43 -0500
commit10ee27a06cc8eb57f83342a8eabcb75deb872d52 (patch)
treed14f69011b7aa1896f1aef37cb2b64f868bce459
parent9931faca02c604c22335f5a935a501bb2ace6e20 (diff)
vfs: re-implement writeback_inodes_sb(_nr)_if_idle() and rename them
writeback_inodes_sb(_nr)_if_idle() is re-implemented by replacing down_read() with down_read_trylock() because - If ->s_umount is write locked, then the sb is not idle. That is writeback_inodes_sb(_nr)_if_idle() needn't wait for the lock. - writeback_inodes_sb(_nr)_if_idle() grabs s_umount lock when it want to start writeback, it may bring us deadlock problem when doing umount. In order to fix the problem, ext4 and btrfs implemented their own writeback functions instead of writeback_inodes_sb(_nr)_if_idle(), but it introduced the redundant code, it is better to implement a new writeback_inodes_sb(_nr)_if_idle(). The name of these two functions is cumbersome, so rename them to try_to_writeback_inodes_sb(_nr). This idea came from Christoph Hellwig. Some code is from the patch of Kamal Mostafa. Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
-rw-r--r--fs/btrfs/extent-tree.c20
-rw-r--r--fs/ext4/inode.c8
-rw-r--r--fs/fs-writeback.c44
-rw-r--r--include/linux/writeback.h6
4 files changed, 28 insertions, 50 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 521e9d4424f6..f31abb14e06f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3689,20 +3689,6 @@ static int can_overcommit(struct btrfs_root *root,
3689 return 0; 3689 return 0;
3690} 3690}
3691 3691
3692static int writeback_inodes_sb_nr_if_idle_safe(struct super_block *sb,
3693 unsigned long nr_pages,
3694 enum wb_reason reason)
3695{
3696 if (!writeback_in_progress(sb->s_bdi) &&
3697 down_read_trylock(&sb->s_umount)) {
3698 writeback_inodes_sb_nr(sb, nr_pages, reason);
3699 up_read(&sb->s_umount);
3700 return 1;
3701 }
3702
3703 return 0;
3704}
3705
3706/* 3692/*
3707 * shrink metadata reservation for delalloc 3693 * shrink metadata reservation for delalloc
3708 */ 3694 */
@@ -3735,9 +3721,9 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
3735 while (delalloc_bytes && loops < 3) { 3721 while (delalloc_bytes && loops < 3) {
3736 max_reclaim = min(delalloc_bytes, to_reclaim); 3722 max_reclaim = min(delalloc_bytes, to_reclaim);
3737 nr_pages = max_reclaim >> PAGE_CACHE_SHIFT; 3723 nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
3738 writeback_inodes_sb_nr_if_idle_safe(root->fs_info->sb, 3724 try_to_writeback_inodes_sb_nr(root->fs_info->sb,
3739 nr_pages, 3725 nr_pages,
3740 WB_REASON_FS_FREE_SPACE); 3726 WB_REASON_FS_FREE_SPACE);
3741 3727
3742 /* 3728 /*
3743 * We need to wait for the async pages to actually start before 3729 * We need to wait for the async pages to actually start before
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index cbfe13bf5b2a..5f6eef71ff21 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2512,12 +2512,8 @@ static int ext4_nonda_switch(struct super_block *sb)
2512 /* 2512 /*
2513 * Start pushing delalloc when 1/2 of free blocks are dirty. 2513 * Start pushing delalloc when 1/2 of free blocks are dirty.
2514 */ 2514 */
2515 if (dirty_blocks && (free_blocks < 2 * dirty_blocks) && 2515 if (dirty_blocks && (free_blocks < 2 * dirty_blocks))
2516 !writeback_in_progress(sb->s_bdi) && 2516 try_to_writeback_inodes_sb(sb, WB_REASON_FS_FREE_SPACE);
2517 down_read_trylock(&sb->s_umount)) {
2518 writeback_inodes_sb(sb, WB_REASON_FS_FREE_SPACE);
2519 up_read(&sb->s_umount);
2520 }
2521 2517
2522 if (2 * free_blocks < 3 * dirty_blocks || 2518 if (2 * free_blocks < 3 * dirty_blocks ||
2523 free_blocks < (dirty_blocks + EXT4_FREECLUSTERS_WATERMARK)) { 2519 free_blocks < (dirty_blocks + EXT4_FREECLUSTERS_WATERMARK)) {
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 310972b72a66..ad3cc46a743a 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1332,47 +1332,43 @@ void writeback_inodes_sb(struct super_block *sb, enum wb_reason reason)
1332EXPORT_SYMBOL(writeback_inodes_sb); 1332EXPORT_SYMBOL(writeback_inodes_sb);
1333 1333
1334/** 1334/**
1335 * writeback_inodes_sb_if_idle - start writeback if none underway 1335 * try_to_writeback_inodes_sb_nr - try to start writeback if none underway
1336 * @sb: the superblock 1336 * @sb: the superblock
1337 * @reason: reason why some writeback work was initiated 1337 * @nr: the number of pages to write
1338 * @reason: the reason of writeback
1338 * 1339 *
1339 * Invoke writeback_inodes_sb if no writeback is currently underway. 1340 * Invoke writeback_inodes_sb_nr if no writeback is currently underway.
1340 * Returns 1 if writeback was started, 0 if not. 1341 * Returns 1 if writeback was started, 0 if not.
1341 */ 1342 */
1342int writeback_inodes_sb_if_idle(struct super_block *sb, enum wb_reason reason) 1343int try_to_writeback_inodes_sb_nr(struct super_block *sb,
1344 unsigned long nr,
1345 enum wb_reason reason)
1343{ 1346{
1344 if (!writeback_in_progress(sb->s_bdi)) { 1347 if (writeback_in_progress(sb->s_bdi))
1345 down_read(&sb->s_umount);
1346 writeback_inodes_sb(sb, reason);
1347 up_read(&sb->s_umount);
1348 return 1; 1348 return 1;
1349 } else 1349
1350 if (!down_read_trylock(&sb->s_umount))
1350 return 0; 1351 return 0;
1352
1353 writeback_inodes_sb_nr(sb, nr, reason);
1354 up_read(&sb->s_umount);
1355 return 1;
1351} 1356}
1352EXPORT_SYMBOL(writeback_inodes_sb_if_idle); 1357EXPORT_SYMBOL(try_to_writeback_inodes_sb_nr);
1353 1358
1354/** 1359/**
1355 * writeback_inodes_sb_nr_if_idle - start writeback if none underway 1360 * try_to_writeback_inodes_sb - try to start writeback if none underway
1356 * @sb: the superblock 1361 * @sb: the superblock
1357 * @nr: the number of pages to write
1358 * @reason: reason why some writeback work was initiated 1362 * @reason: reason why some writeback work was initiated
1359 * 1363 *
1360 * Invoke writeback_inodes_sb if no writeback is currently underway. 1364 * Implement by try_to_writeback_inodes_sb_nr()
1361 * Returns 1 if writeback was started, 0 if not. 1365 * Returns 1 if writeback was started, 0 if not.
1362 */ 1366 */
1363int writeback_inodes_sb_nr_if_idle(struct super_block *sb, 1367int try_to_writeback_inodes_sb(struct super_block *sb, enum wb_reason reason)
1364 unsigned long nr,
1365 enum wb_reason reason)
1366{ 1368{
1367 if (!writeback_in_progress(sb->s_bdi)) { 1369 return try_to_writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason);
1368 down_read(&sb->s_umount);
1369 writeback_inodes_sb_nr(sb, nr, reason);
1370 up_read(&sb->s_umount);
1371 return 1;
1372 } else
1373 return 0;
1374} 1370}
1375EXPORT_SYMBOL(writeback_inodes_sb_nr_if_idle); 1371EXPORT_SYMBOL(try_to_writeback_inodes_sb);
1376 1372
1377/** 1373/**
1378 * sync_inodes_sb - sync sb inode pages 1374 * sync_inodes_sb - sync sb inode pages
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index b82a83aba311..9a9367c0c076 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -87,9 +87,9 @@ int inode_wait(void *);
87void writeback_inodes_sb(struct super_block *, enum wb_reason reason); 87void writeback_inodes_sb(struct super_block *, enum wb_reason reason);
88void writeback_inodes_sb_nr(struct super_block *, unsigned long nr, 88void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
89 enum wb_reason reason); 89 enum wb_reason reason);
90int writeback_inodes_sb_if_idle(struct super_block *, enum wb_reason reason); 90int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
91int writeback_inodes_sb_nr_if_idle(struct super_block *, unsigned long nr, 91int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
92 enum wb_reason reason); 92 enum wb_reason reason);
93void sync_inodes_sb(struct super_block *); 93void sync_inodes_sb(struct super_block *);
94long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, 94long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
95 enum wb_reason reason); 95 enum wb_reason reason);