diff options
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 5c46ed9f3e14..fee81e8768c9 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -281,13 +281,15 @@ locked_inode_to_wb_and_lock_list(struct inode *inode) | |||
281 | wb_get(wb); | 281 | wb_get(wb); |
282 | spin_unlock(&inode->i_lock); | 282 | spin_unlock(&inode->i_lock); |
283 | spin_lock(&wb->list_lock); | 283 | spin_lock(&wb->list_lock); |
284 | wb_put(wb); /* not gonna deref it anymore */ | ||
285 | 284 | ||
286 | /* i_wb may have changed inbetween, can't use inode_to_wb() */ | 285 | /* i_wb may have changed inbetween, can't use inode_to_wb() */ |
287 | if (likely(wb == inode->i_wb)) | 286 | if (likely(wb == inode->i_wb)) { |
288 | return wb; /* @inode already has ref */ | 287 | wb_put(wb); /* @inode already has ref */ |
288 | return wb; | ||
289 | } | ||
289 | 290 | ||
290 | spin_unlock(&wb->list_lock); | 291 | spin_unlock(&wb->list_lock); |
292 | wb_put(wb); | ||
291 | cpu_relax(); | 293 | cpu_relax(); |
292 | spin_lock(&inode->i_lock); | 294 | spin_lock(&inode->i_lock); |
293 | } | 295 | } |
@@ -1337,10 +1339,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
1337 | * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode() | 1339 | * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode() |
1338 | * and does more profound writeback list handling in writeback_sb_inodes(). | 1340 | * and does more profound writeback list handling in writeback_sb_inodes(). |
1339 | */ | 1341 | */ |
1340 | static int | 1342 | static int writeback_single_inode(struct inode *inode, |
1341 | writeback_single_inode(struct inode *inode, struct bdi_writeback *wb, | 1343 | struct writeback_control *wbc) |
1342 | struct writeback_control *wbc) | ||
1343 | { | 1344 | { |
1345 | struct bdi_writeback *wb; | ||
1344 | int ret = 0; | 1346 | int ret = 0; |
1345 | 1347 | ||
1346 | spin_lock(&inode->i_lock); | 1348 | spin_lock(&inode->i_lock); |
@@ -1378,7 +1380,8 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb, | |||
1378 | ret = __writeback_single_inode(inode, wbc); | 1380 | ret = __writeback_single_inode(inode, wbc); |
1379 | 1381 | ||
1380 | wbc_detach_inode(wbc); | 1382 | wbc_detach_inode(wbc); |
1381 | spin_lock(&wb->list_lock); | 1383 | |
1384 | wb = inode_to_wb_and_lock_list(inode); | ||
1382 | spin_lock(&inode->i_lock); | 1385 | spin_lock(&inode->i_lock); |
1383 | /* | 1386 | /* |
1384 | * If inode is clean, remove it from writeback lists. Otherwise don't | 1387 | * If inode is clean, remove it from writeback lists. Otherwise don't |
@@ -1453,6 +1456,7 @@ static long writeback_sb_inodes(struct super_block *sb, | |||
1453 | 1456 | ||
1454 | while (!list_empty(&wb->b_io)) { | 1457 | while (!list_empty(&wb->b_io)) { |
1455 | struct inode *inode = wb_inode(wb->b_io.prev); | 1458 | struct inode *inode = wb_inode(wb->b_io.prev); |
1459 | struct bdi_writeback *tmp_wb; | ||
1456 | 1460 | ||
1457 | if (inode->i_sb != sb) { | 1461 | if (inode->i_sb != sb) { |
1458 | if (work->sb) { | 1462 | if (work->sb) { |
@@ -1543,15 +1547,23 @@ static long writeback_sb_inodes(struct super_block *sb, | |||
1543 | cond_resched(); | 1547 | cond_resched(); |
1544 | } | 1548 | } |
1545 | 1549 | ||
1546 | 1550 | /* | |
1547 | spin_lock(&wb->list_lock); | 1551 | * Requeue @inode if still dirty. Be careful as @inode may |
1552 | * have been switched to another wb in the meantime. | ||
1553 | */ | ||
1554 | tmp_wb = inode_to_wb_and_lock_list(inode); | ||
1548 | spin_lock(&inode->i_lock); | 1555 | spin_lock(&inode->i_lock); |
1549 | if (!(inode->i_state & I_DIRTY_ALL)) | 1556 | if (!(inode->i_state & I_DIRTY_ALL)) |
1550 | wrote++; | 1557 | wrote++; |
1551 | requeue_inode(inode, wb, &wbc); | 1558 | requeue_inode(inode, tmp_wb, &wbc); |
1552 | inode_sync_complete(inode); | 1559 | inode_sync_complete(inode); |
1553 | spin_unlock(&inode->i_lock); | 1560 | spin_unlock(&inode->i_lock); |
1554 | 1561 | ||
1562 | if (unlikely(tmp_wb != wb)) { | ||
1563 | spin_unlock(&tmp_wb->list_lock); | ||
1564 | spin_lock(&wb->list_lock); | ||
1565 | } | ||
1566 | |||
1555 | /* | 1567 | /* |
1556 | * bail out to wb_writeback() often enough to check | 1568 | * bail out to wb_writeback() often enough to check |
1557 | * background threshold and other termination conditions. | 1569 | * background threshold and other termination conditions. |
@@ -2338,7 +2350,6 @@ EXPORT_SYMBOL(sync_inodes_sb); | |||
2338 | */ | 2350 | */ |
2339 | int write_inode_now(struct inode *inode, int sync) | 2351 | int write_inode_now(struct inode *inode, int sync) |
2340 | { | 2352 | { |
2341 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; | ||
2342 | struct writeback_control wbc = { | 2353 | struct writeback_control wbc = { |
2343 | .nr_to_write = LONG_MAX, | 2354 | .nr_to_write = LONG_MAX, |
2344 | .sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE, | 2355 | .sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE, |
@@ -2350,7 +2361,7 @@ int write_inode_now(struct inode *inode, int sync) | |||
2350 | wbc.nr_to_write = 0; | 2361 | wbc.nr_to_write = 0; |
2351 | 2362 | ||
2352 | might_sleep(); | 2363 | might_sleep(); |
2353 | return writeback_single_inode(inode, wb, &wbc); | 2364 | return writeback_single_inode(inode, &wbc); |
2354 | } | 2365 | } |
2355 | EXPORT_SYMBOL(write_inode_now); | 2366 | EXPORT_SYMBOL(write_inode_now); |
2356 | 2367 | ||
@@ -2367,7 +2378,7 @@ EXPORT_SYMBOL(write_inode_now); | |||
2367 | */ | 2378 | */ |
2368 | int sync_inode(struct inode *inode, struct writeback_control *wbc) | 2379 | int sync_inode(struct inode *inode, struct writeback_control *wbc) |
2369 | { | 2380 | { |
2370 | return writeback_single_inode(inode, &inode_to_bdi(inode)->wb, wbc); | 2381 | return writeback_single_inode(inode, wbc); |
2371 | } | 2382 | } |
2372 | EXPORT_SYMBOL(sync_inode); | 2383 | EXPORT_SYMBOL(sync_inode); |
2373 | 2384 | ||