|
@@ -1339,10 +1339,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
|
|
|
* we go e.g. from filesystem. Flusher thread uses __writeback_single_inode()
|
|
|
* and does more profound writeback list handling in writeback_sb_inodes().
|
|
|
*/
|
|
|
-static int
|
|
|
-writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
|
|
|
- struct writeback_control *wbc)
|
|
|
+static int writeback_single_inode(struct inode *inode,
|
|
|
+ struct writeback_control *wbc)
|
|
|
{
|
|
|
+ struct bdi_writeback *wb;
|
|
|
int ret = 0;
|
|
|
|
|
|
spin_lock(&inode->i_lock);
|
|
@@ -1380,7 +1380,8 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
|
|
|
ret = __writeback_single_inode(inode, wbc);
|
|
|
|
|
|
wbc_detach_inode(wbc);
|
|
|
- spin_lock(&wb->list_lock);
|
|
|
+
|
|
|
+ wb = inode_to_wb_and_lock_list(inode);
|
|
|
spin_lock(&inode->i_lock);
|
|
|
/*
|
|
|
* If inode is clean, remove it from writeback lists. Otherwise don't
|
|
@@ -1455,6 +1456,7 @@ static long writeback_sb_inodes(struct super_block *sb,
|
|
|
|
|
|
while (!list_empty(&wb->b_io)) {
|
|
|
struct inode *inode = wb_inode(wb->b_io.prev);
|
|
|
+ struct bdi_writeback *tmp_wb;
|
|
|
|
|
|
if (inode->i_sb != sb) {
|
|
|
if (work->sb) {
|
|
@@ -1545,15 +1547,23 @@ static long writeback_sb_inodes(struct super_block *sb,
|
|
|
cond_resched();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- spin_lock(&wb->list_lock);
|
|
|
+ /*
|
|
|
+ * Requeue @inode if still dirty. Be careful as @inode may
|
|
|
+ * have been switched to another wb in the meantime.
|
|
|
+ */
|
|
|
+ tmp_wb = inode_to_wb_and_lock_list(inode);
|
|
|
spin_lock(&inode->i_lock);
|
|
|
if (!(inode->i_state & I_DIRTY_ALL))
|
|
|
wrote++;
|
|
|
- requeue_inode(inode, wb, &wbc);
|
|
|
+ requeue_inode(inode, tmp_wb, &wbc);
|
|
|
inode_sync_complete(inode);
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
|
|
|
+ if (unlikely(tmp_wb != wb)) {
|
|
|
+ spin_unlock(&tmp_wb->list_lock);
|
|
|
+ spin_lock(&wb->list_lock);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* bail out to wb_writeback() often enough to check
|
|
|
* background threshold and other termination conditions.
|
|
@@ -2340,7 +2350,6 @@ EXPORT_SYMBOL(sync_inodes_sb);
|
|
|
*/
|
|
|
int write_inode_now(struct inode *inode, int sync)
|
|
|
{
|
|
|
- struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
|
|
|
struct writeback_control wbc = {
|
|
|
.nr_to_write = LONG_MAX,
|
|
|
.sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE,
|
|
@@ -2352,7 +2361,7 @@ int write_inode_now(struct inode *inode, int sync)
|
|
|
wbc.nr_to_write = 0;
|
|
|
|
|
|
might_sleep();
|
|
|
- return writeback_single_inode(inode, wb, &wbc);
|
|
|
+ return writeback_single_inode(inode, &wbc);
|
|
|
}
|
|
|
EXPORT_SYMBOL(write_inode_now);
|
|
|
|
|
@@ -2369,7 +2378,7 @@ EXPORT_SYMBOL(write_inode_now);
|
|
|
*/
|
|
|
int sync_inode(struct inode *inode, struct writeback_control *wbc)
|
|
|
{
|
|
|
- return writeback_single_inode(inode, &inode_to_bdi(inode)->wb, wbc);
|
|
|
+ return writeback_single_inode(inode, wbc);
|
|
|
}
|
|
|
EXPORT_SYMBOL(sync_inode);
|
|
|
|