diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2010-05-18 08:29:29 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2010-05-21 14:00:25 -0400 |
commit | 7c8a3554c683f512dbcee26faedb42e4c05f12fa (patch) | |
tree | ece0d1b79ccc1f596b0ccd0217b584c27a3ff414 /fs/fs-writeback.c | |
parent | 2db4e42eaceabec42f738f3895300632cd375e67 (diff) |
writeback: ensure that WB_SYNC_NONE writeback with sb pinned is sync
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>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | 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 0f629571234f..76f546d56a64 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) | |||
193 | } | 193 | } |
194 | 194 | ||
195 | static void bdi_alloc_queue_work(struct backing_dev_info *bdi, | 195 | static void bdi_alloc_queue_work(struct backing_dev_info *bdi, |
196 | struct wb_writeback_args *args) | 196 | struct wb_writeback_args *args, |
197 | int wait) | ||
197 | { | 198 | { |
198 | struct bdi_work *work; | 199 | struct bdi_work *work; |
199 | 200 | ||
@@ -205,6 +206,8 @@ static void bdi_alloc_queue_work(struct backing_dev_info *bdi, | |||
205 | if (work) { | 206 | if (work) { |
206 | bdi_work_init(work, args); | 207 | bdi_work_init(work, args); |
207 | bdi_queue_work(bdi, work); | 208 | bdi_queue_work(bdi, work); |
209 | if (wait) | ||
210 | bdi_wait_on_work_clear(work); | ||
208 | } else { | 211 | } else { |
209 | struct bdi_writeback *wb = &bdi->wb; | 212 | struct bdi_writeback *wb = &bdi->wb; |
210 | 213 | ||
@@ -279,7 +282,7 @@ void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb, | |||
279 | args.for_background = 1; | 282 | args.for_background = 1; |
280 | } | 283 | } |
281 | 284 | ||
282 | bdi_alloc_queue_work(bdi, &args); | 285 | bdi_alloc_queue_work(bdi, &args, sb_locked); |
283 | } | 286 | } |
284 | 287 | ||
285 | /* | 288 | /* |
@@ -909,6 +912,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
909 | 912 | ||
910 | while ((work = get_next_work_item(bdi, wb)) != NULL) { | 913 | while ((work = get_next_work_item(bdi, wb)) != NULL) { |
911 | struct wb_writeback_args args = work->args; | 914 | struct wb_writeback_args args = work->args; |
915 | int post_clear; | ||
912 | 916 | ||
913 | /* | 917 | /* |
914 | * Override sync mode, in case we must wait for completion | 918 | * 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) | |||
916 | if (force_wait) | 920 | if (force_wait) |
917 | work->args.sync_mode = args.sync_mode = WB_SYNC_ALL; | 921 | work->args.sync_mode = args.sync_mode = WB_SYNC_ALL; |
918 | 922 | ||
923 | post_clear = WB_SYNC_ALL || args.sb_pinned; | ||
924 | |||
919 | /* | 925 | /* |
920 | * If this isn't a data integrity operation, just notify | 926 | * If this isn't a data integrity operation, just notify |
921 | * that we have seen this work and we are now starting it. | 927 | * that we have seen this work and we are now starting it. |
922 | */ | 928 | */ |
923 | if (args.sync_mode == WB_SYNC_NONE) | 929 | if (!post_clear) |
924 | wb_clear_pending(wb, work); | 930 | wb_clear_pending(wb, work); |
925 | 931 | ||
926 | wrote += wb_writeback(wb, &args); | 932 | wrote += wb_writeback(wb, &args); |
@@ -929,7 +935,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
929 | * This is a data integrity writeback, so only do the | 935 | * This is a data integrity writeback, so only do the |
930 | * notification when we have completed the work. | 936 | * notification when we have completed the work. |
931 | */ | 937 | */ |
932 | if (args.sync_mode == WB_SYNC_ALL) | 938 | if (post_clear) |
933 | wb_clear_pending(wb, work); | 939 | wb_clear_pending(wb, work); |
934 | } | 940 | } |
935 | 941 | ||
@@ -1000,7 +1006,7 @@ static void bdi_writeback_all(struct super_block *sb, long nr_pages) | |||
1000 | if (!bdi_has_dirty_io(bdi)) | 1006 | if (!bdi_has_dirty_io(bdi)) |
1001 | continue; | 1007 | continue; |
1002 | 1008 | ||
1003 | bdi_alloc_queue_work(bdi, &args); | 1009 | bdi_alloc_queue_work(bdi, &args, 0); |
1004 | } | 1010 | } |
1005 | 1011 | ||
1006 | rcu_read_unlock(); | 1012 | rcu_read_unlock(); |