diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2013-04-29 18:07:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 18:54:33 -0400 |
commit | 7136851117744f1d291bed6d307432699d405109 (patch) | |
tree | 6dc7d6bef45e24ad0d3d5d1b9290a81109758172 /fs | |
parent | 106c992a5ebef28193cf5958e49ceff5e4aebb04 (diff) |
mm: make snapshotting pages for stable writes a per-bio operation
Walking a bio's page mappings has proved problematic, so create a new
bio flag to indicate that a bio's data needs to be snapshotted in order
to guarantee stable pages during writeback. Next, for the one user
(ext3/jbd) of snapshotting, hook all the places where writes can be
initiated without PG_writeback set, and set BIO_SNAP_STABLE there.
We must also flag journal "metadata" bios for stable writeout, since
file data can be written through the journal. Finally, the
MS_SNAP_STABLE mount flag (only used by ext3) is now superfluous, so get
rid of it.
[akpm@linux-foundation.org: rename _submit_bh()'s `flags' to `bio_flags', delobotomize the _submit_bh declaration]
[akpm@linux-foundation.org: teeny cleanup]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Artem Bityutskiy <dedekind1@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/buffer.c | 9 | ||||
-rw-r--r-- | fs/ext3/super.c | 1 | ||||
-rw-r--r-- | fs/jbd/commit.c | 25 |
3 files changed, 30 insertions, 5 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index b4dcb34c9635..71578d69b82d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2949,7 +2949,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh) | |||
2949 | } | 2949 | } |
2950 | } | 2950 | } |
2951 | 2951 | ||
2952 | int submit_bh(int rw, struct buffer_head * bh) | 2952 | int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags) |
2953 | { | 2953 | { |
2954 | struct bio *bio; | 2954 | struct bio *bio; |
2955 | int ret = 0; | 2955 | int ret = 0; |
@@ -2984,6 +2984,7 @@ int submit_bh(int rw, struct buffer_head * bh) | |||
2984 | 2984 | ||
2985 | bio->bi_end_io = end_bio_bh_io_sync; | 2985 | bio->bi_end_io = end_bio_bh_io_sync; |
2986 | bio->bi_private = bh; | 2986 | bio->bi_private = bh; |
2987 | bio->bi_flags |= bio_flags; | ||
2987 | 2988 | ||
2988 | /* Take care of bh's that straddle the end of the device */ | 2989 | /* Take care of bh's that straddle the end of the device */ |
2989 | guard_bh_eod(rw, bio, bh); | 2990 | guard_bh_eod(rw, bio, bh); |
@@ -2997,6 +2998,12 @@ int submit_bh(int rw, struct buffer_head * bh) | |||
2997 | bio_put(bio); | 2998 | bio_put(bio); |
2998 | return ret; | 2999 | return ret; |
2999 | } | 3000 | } |
3001 | EXPORT_SYMBOL_GPL(_submit_bh); | ||
3002 | |||
3003 | int submit_bh(int rw, struct buffer_head *bh) | ||
3004 | { | ||
3005 | return _submit_bh(rw, bh, 0); | ||
3006 | } | ||
3000 | EXPORT_SYMBOL(submit_bh); | 3007 | EXPORT_SYMBOL(submit_bh); |
3001 | 3008 | ||
3002 | /** | 3009 | /** |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index fb5120a5505c..3dc48cc8b6eb 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -2067,7 +2067,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
2067 | test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": | 2067 | test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": |
2068 | test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": | 2068 | test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": |
2069 | "writeback"); | 2069 | "writeback"); |
2070 | sb->s_flags |= MS_SNAP_STABLE; | ||
2071 | 2070 | ||
2072 | return 0; | 2071 | return 0; |
2073 | 2072 | ||
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 86b39b167c23..11bb11f48b3a 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -162,8 +162,17 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs, | |||
162 | 162 | ||
163 | for (i = 0; i < bufs; i++) { | 163 | for (i = 0; i < bufs; i++) { |
164 | wbuf[i]->b_end_io = end_buffer_write_sync; | 164 | wbuf[i]->b_end_io = end_buffer_write_sync; |
165 | /* We use-up our safety reference in submit_bh() */ | 165 | /* |
166 | submit_bh(write_op, wbuf[i]); | 166 | * Here we write back pagecache data that may be mmaped. Since |
167 | * we cannot afford to clean the page and set PageWriteback | ||
168 | * here due to lock ordering (page lock ranks above transaction | ||
169 | * start), the data can change while IO is in flight. Tell the | ||
170 | * block layer it should bounce the bio pages if stable data | ||
171 | * during write is required. | ||
172 | * | ||
173 | * We use up our safety reference in submit_bh(). | ||
174 | */ | ||
175 | _submit_bh(write_op, wbuf[i], 1 << BIO_SNAP_STABLE); | ||
167 | } | 176 | } |
168 | } | 177 | } |
169 | 178 | ||
@@ -667,7 +676,17 @@ start_journal_io: | |||
667 | clear_buffer_dirty(bh); | 676 | clear_buffer_dirty(bh); |
668 | set_buffer_uptodate(bh); | 677 | set_buffer_uptodate(bh); |
669 | bh->b_end_io = journal_end_buffer_io_sync; | 678 | bh->b_end_io = journal_end_buffer_io_sync; |
670 | submit_bh(write_op, bh); | 679 | /* |
680 | * In data=journal mode, here we can end up | ||
681 | * writing pagecache data that might be | ||
682 | * mmapped. Since we can't afford to clean the | ||
683 | * page and set PageWriteback (see the comment | ||
684 | * near the other use of _submit_bh()), the | ||
685 | * data can change while the write is in | ||
686 | * flight. Tell the block layer to bounce the | ||
687 | * bio pages if stable pages are required. | ||
688 | */ | ||
689 | _submit_bh(write_op, bh, 1 << BIO_SNAP_STABLE); | ||
671 | } | 690 | } |
672 | cond_resched(); | 691 | cond_resched(); |
673 | 692 | ||