diff options
author | Tejun Heo <tj@kernel.org> | 2014-09-07 19:04:01 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-09-08 12:00:43 -0400 |
commit | 018a17bdc8658ad448497c84d4ba21b6985820ec (patch) | |
tree | 77bfb4ea1b75452dd68817d59770e8d1c6bd37ec /fs/block_dev.c | |
parent | 1a1e4530eacca37e85a4d66a164273c7dba9110c (diff) |
bdi: reimplement bdev_inode_switch_bdi()
A block_device may be attached to different gendisks and thus
different bdis over time. bdev_inode_switch_bdi() is used to switch
the associated bdi. The function assumes that the inode could be
dirty and transfers it between bdis if so. This is a bit nasty in
that it reaches into bdi internals.
This patch reimplements the function so that it writes out the inode
if dirty. This is a lot simpler and can be implemented without
exposing bdi internals.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 32 |
1 files changed, 11 insertions, 21 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index d3251eca6429..cc8d68ac29aa 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -50,32 +50,22 @@ inline struct block_device *I_BDEV(struct inode *inode) | |||
50 | EXPORT_SYMBOL(I_BDEV); | 50 | EXPORT_SYMBOL(I_BDEV); |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * Move the inode from its current bdi to a new bdi. If the inode is dirty we | 53 | * Move the inode from its current bdi to a new bdi. Make sure the inode |
54 | * need to move it onto the dirty list of @dst so that the inode is always on | 54 | * is clean before moving so that it doesn't linger on the old bdi. |
55 | * the right list. | ||
56 | */ | 55 | */ |
57 | static void bdev_inode_switch_bdi(struct inode *inode, | 56 | static void bdev_inode_switch_bdi(struct inode *inode, |
58 | struct backing_dev_info *dst) | 57 | struct backing_dev_info *dst) |
59 | { | 58 | { |
60 | struct backing_dev_info *old = inode->i_data.backing_dev_info; | 59 | while (true) { |
61 | bool wakeup_bdi = false; | 60 | spin_lock(&inode->i_lock); |
62 | 61 | if (!(inode->i_state & I_DIRTY)) { | |
63 | if (unlikely(dst == old)) /* deadlock avoidance */ | 62 | inode->i_data.backing_dev_info = dst; |
64 | return; | 63 | spin_unlock(&inode->i_lock); |
65 | bdi_lock_two(&old->wb, &dst->wb); | 64 | return; |
66 | spin_lock(&inode->i_lock); | 65 | } |
67 | inode->i_data.backing_dev_info = dst; | 66 | spin_unlock(&inode->i_lock); |
68 | if (inode->i_state & I_DIRTY) { | 67 | WARN_ON_ONCE(write_inode_now(inode, true)); |
69 | if (bdi_cap_writeback_dirty(dst) && !wb_has_dirty_io(&dst->wb)) | ||
70 | wakeup_bdi = true; | ||
71 | list_move(&inode->i_wb_list, &dst->wb.b_dirty); | ||
72 | } | 68 | } |
73 | spin_unlock(&inode->i_lock); | ||
74 | spin_unlock(&old->wb.list_lock); | ||
75 | spin_unlock(&dst->wb.list_lock); | ||
76 | |||
77 | if (wakeup_bdi) | ||
78 | bdi_wakeup_thread_delayed(dst); | ||
79 | } | 69 | } |
80 | 70 | ||
81 | /* Kill _all_ buffers and pagecache , dirty or not.. */ | 71 | /* Kill _all_ buffers and pagecache , dirty or not.. */ |