Patchwork [2/2] writeback: ensure that WB_SYNC_NONE writeback with sb pinned is sync

login
register
mail settings
Submitter Stefan Bader
Date June 2, 2010, 1:09 p.m.
Message ID <1275484147-26044-3-git-send-email-stefan.bader@canonical.com>
Download mbox | patch
Permalink /patch/54371/
State Rejected
Delegated to: Stefan Bader
Headers show

Comments

Stefan Bader - June 2, 2010, 1:09 p.m.
From: Jens Axboe <jens.axboe@oracle.com>

BugLink: http://launchpad.net/bugs/543617

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>
(cherry-picked from commit 7c8a3554c683f512dbcee26faedb42e4c05f12fa upstream)
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
---
 fs/fs-writeback.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

Patch

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 3ec332d..d755d68 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -192,7 +192,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;
 
@@ -204,6 +205,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;
 
@@ -277,7 +280,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);
 }
 
 /*
@@ -903,6 +906,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
@@ -910,11 +914,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);
@@ -923,7 +929,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);
 	}
 
@@ -990,7 +996,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();