94 lines
2.7 KiB
Diff
94 lines
2.7 KiB
Diff
From: Jens Axboe <jens.axboe@oracle.com>
|
|
Date: Tue, 18 May 2010 14:29:29 +0200
|
|
Subject: [PATCH 4/5] writeback: ensure that WB_SYNC_NONE writeback with sb pinned is sync
|
|
|
|
commit 7c8a3554c683f512dbcee26faedb42e4c05f12fa upstream.
|
|
|
|
Even if the writeout itself isn't a data integrity operation, we need
|
|
to ensure that the caller doesn't drop the sb umount sem before we
|
|
have actually done the writeback.
|
|
|
|
This is a fixup for commit e913fc82.
|
|
|
|
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
|
|
---
|
|
fs/fs-writeback.c | 16 +++++++++++-----
|
|
1 files changed, 11 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
|
|
index 0f62957..76f546d 100644
|
|
--- a/fs/fs-writeback.c
|
|
+++ b/fs/fs-writeback.c
|
|
@@ -193,7 +193,8 @@ static void bdi_wait_on_work_clear(struct bdi_work *work)
|
|
}
|
|
|
|
static void bdi_alloc_queue_work(struct backing_dev_info *bdi,
|
|
- struct wb_writeback_args *args)
|
|
+ struct wb_writeback_args *args,
|
|
+ int wait)
|
|
{
|
|
struct bdi_work *work;
|
|
|
|
@@ -205,6 +206,8 @@ static void bdi_alloc_queue_work(struct backing_dev_info *bdi,
|
|
if (work) {
|
|
bdi_work_init(work, args);
|
|
bdi_queue_work(bdi, work);
|
|
+ if (wait)
|
|
+ bdi_wait_on_work_clear(work);
|
|
} else {
|
|
struct bdi_writeback *wb = &bdi->wb;
|
|
|
|
@@ -279,7 +282,7 @@ void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
|
|
args.for_background = 1;
|
|
}
|
|
|
|
- bdi_alloc_queue_work(bdi, &args);
|
|
+ bdi_alloc_queue_work(bdi, &args, sb_locked);
|
|
}
|
|
|
|
/*
|
|
@@ -909,6 +912,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
|
|
|
|
while ((work = get_next_work_item(bdi, wb)) != NULL) {
|
|
struct wb_writeback_args args = work->args;
|
|
+ int post_clear;
|
|
|
|
/*
|
|
* Override sync mode, in case we must wait for completion
|
|
@@ -916,11 +920,13 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
|
|
if (force_wait)
|
|
work->args.sync_mode = args.sync_mode = WB_SYNC_ALL;
|
|
|
|
+ post_clear = WB_SYNC_ALL || args.sb_pinned;
|
|
+
|
|
/*
|
|
* If this isn't a data integrity operation, just notify
|
|
* that we have seen this work and we are now starting it.
|
|
*/
|
|
- if (args.sync_mode == WB_SYNC_NONE)
|
|
+ if (!post_clear)
|
|
wb_clear_pending(wb, work);
|
|
|
|
wrote += wb_writeback(wb, &args);
|
|
@@ -929,7 +935,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
|
|
* This is a data integrity writeback, so only do the
|
|
* notification when we have completed the work.
|
|
*/
|
|
- if (args.sync_mode == WB_SYNC_ALL)
|
|
+ if (post_clear)
|
|
wb_clear_pending(wb, work);
|
|
}
|
|
|
|
@@ -1000,7 +1006,7 @@ static void bdi_writeback_all(struct super_block *sb, long nr_pages)
|
|
if (!bdi_has_dirty_io(bdi))
|
|
continue;
|
|
|
|
- bdi_alloc_queue_work(bdi, &args);
|
|
+ bdi_alloc_queue_work(bdi, &args, 0);
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
--
|
|
1.7.1
|
|
|