diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-05-11 19:07:42 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-05-11 19:07:42 -0400 |
commit | a549984b8c95acbecefd1fdd4bfdbea4d29b0588 (patch) | |
tree | eb25bf90acc6c084de08616ebb26ee091158c46e /fs/ext4/page-io.c | |
parent | e6155736ad76b2070652745f9e54cdea3f0d8567 (diff) |
ext4: revert "ext4: use io_end for multiple bios"
This reverts commit 4eec708d263f0ee10861d69251708a225b64cac7.
Multiple users have reported crashes which is apparently caused by
this commit. Thanks to Dmitry Monakhov for bisecting it.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: Dmitry Monakhov <dmonakhov@openvz.org>
Cc: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext4/page-io.c')
-rw-r--r-- | fs/ext4/page-io.c | 121 |
1 files changed, 45 insertions, 76 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 5929cd0baa20..6626aba57ebb 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
@@ -61,28 +61,15 @@ void ext4_ioend_shutdown(struct inode *inode) | |||
61 | cancel_work_sync(&EXT4_I(inode)->i_unwritten_work); | 61 | cancel_work_sync(&EXT4_I(inode)->i_unwritten_work); |
62 | } | 62 | } |
63 | 63 | ||
64 | static void ext4_release_io_end(ext4_io_end_t *io_end) | 64 | void ext4_free_io_end(ext4_io_end_t *io) |
65 | { | 65 | { |
66 | BUG_ON(!list_empty(&io_end->list)); | 66 | BUG_ON(!io); |
67 | BUG_ON(io_end->flag & EXT4_IO_END_UNWRITTEN); | 67 | BUG_ON(!list_empty(&io->list)); |
68 | 68 | BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); | |
69 | if (atomic_dec_and_test(&EXT4_I(io_end->inode)->i_ioend_count)) | ||
70 | wake_up_all(ext4_ioend_wq(io_end->inode)); | ||
71 | if (io_end->flag & EXT4_IO_END_DIRECT) | ||
72 | inode_dio_done(io_end->inode); | ||
73 | if (io_end->iocb) | ||
74 | aio_complete(io_end->iocb, io_end->result, 0); | ||
75 | kmem_cache_free(io_end_cachep, io_end); | ||
76 | } | ||
77 | |||
78 | static void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end) | ||
79 | { | ||
80 | struct inode *inode = io_end->inode; | ||
81 | 69 | ||
82 | io_end->flag &= ~EXT4_IO_END_UNWRITTEN; | 70 | if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count)) |
83 | /* Wake up anyone waiting on unwritten extent conversion */ | 71 | wake_up_all(ext4_ioend_wq(io->inode)); |
84 | if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) | 72 | kmem_cache_free(io_end_cachep, io); |
85 | wake_up_all(ext4_ioend_wq(inode)); | ||
86 | } | 73 | } |
87 | 74 | ||
88 | /* check a range of space and convert unwritten extents to written. */ | 75 | /* check a range of space and convert unwritten extents to written. */ |
@@ -105,8 +92,13 @@ static int ext4_end_io(ext4_io_end_t *io) | |||
105 | "(inode %lu, offset %llu, size %zd, error %d)", | 92 | "(inode %lu, offset %llu, size %zd, error %d)", |
106 | inode->i_ino, offset, size, ret); | 93 | inode->i_ino, offset, size, ret); |
107 | } | 94 | } |
108 | ext4_clear_io_unwritten_flag(io); | 95 | /* Wake up anyone waiting on unwritten extent conversion */ |
109 | ext4_release_io_end(io); | 96 | if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) |
97 | wake_up_all(ext4_ioend_wq(inode)); | ||
98 | if (io->flag & EXT4_IO_END_DIRECT) | ||
99 | inode_dio_done(inode); | ||
100 | if (io->iocb) | ||
101 | aio_complete(io->iocb, io->result, 0); | ||
110 | return ret; | 102 | return ret; |
111 | } | 103 | } |
112 | 104 | ||
@@ -137,7 +129,7 @@ static void dump_completed_IO(struct inode *inode) | |||
137 | } | 129 | } |
138 | 130 | ||
139 | /* Add the io_end to per-inode completed end_io list. */ | 131 | /* Add the io_end to per-inode completed end_io list. */ |
140 | static void ext4_add_complete_io(ext4_io_end_t *io_end) | 132 | void ext4_add_complete_io(ext4_io_end_t *io_end) |
141 | { | 133 | { |
142 | struct ext4_inode_info *ei = EXT4_I(io_end->inode); | 134 | struct ext4_inode_info *ei = EXT4_I(io_end->inode); |
143 | struct workqueue_struct *wq; | 135 | struct workqueue_struct *wq; |
@@ -174,6 +166,8 @@ static int ext4_do_flush_completed_IO(struct inode *inode) | |||
174 | err = ext4_end_io(io); | 166 | err = ext4_end_io(io); |
175 | if (unlikely(!ret && err)) | 167 | if (unlikely(!ret && err)) |
176 | ret = err; | 168 | ret = err; |
169 | io->flag &= ~EXT4_IO_END_UNWRITTEN; | ||
170 | ext4_free_io_end(io); | ||
177 | } | 171 | } |
178 | return ret; | 172 | return ret; |
179 | } | 173 | } |
@@ -205,43 +199,10 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) | |||
205 | atomic_inc(&EXT4_I(inode)->i_ioend_count); | 199 | atomic_inc(&EXT4_I(inode)->i_ioend_count); |
206 | io->inode = inode; | 200 | io->inode = inode; |
207 | INIT_LIST_HEAD(&io->list); | 201 | INIT_LIST_HEAD(&io->list); |
208 | atomic_set(&io->count, 1); | ||
209 | } | 202 | } |
210 | return io; | 203 | return io; |
211 | } | 204 | } |
212 | 205 | ||
213 | void ext4_put_io_end_defer(ext4_io_end_t *io_end) | ||
214 | { | ||
215 | if (atomic_dec_and_test(&io_end->count)) { | ||
216 | if (!(io_end->flag & EXT4_IO_END_UNWRITTEN) || !io_end->size) { | ||
217 | ext4_release_io_end(io_end); | ||
218 | return; | ||
219 | } | ||
220 | ext4_add_complete_io(io_end); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | int ext4_put_io_end(ext4_io_end_t *io_end) | ||
225 | { | ||
226 | int err = 0; | ||
227 | |||
228 | if (atomic_dec_and_test(&io_end->count)) { | ||
229 | if (io_end->flag & EXT4_IO_END_UNWRITTEN) { | ||
230 | err = ext4_convert_unwritten_extents(io_end->inode, | ||
231 | io_end->offset, io_end->size); | ||
232 | ext4_clear_io_unwritten_flag(io_end); | ||
233 | } | ||
234 | ext4_release_io_end(io_end); | ||
235 | } | ||
236 | return err; | ||
237 | } | ||
238 | |||
239 | ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) | ||
240 | { | ||
241 | atomic_inc(&io_end->count); | ||
242 | return io_end; | ||
243 | } | ||
244 | |||
245 | /* | 206 | /* |
246 | * Print an buffer I/O error compatible with the fs/buffer.c. This | 207 | * Print an buffer I/O error compatible with the fs/buffer.c. This |
247 | * provides compatibility with dmesg scrapers that look for a specific | 208 | * provides compatibility with dmesg scrapers that look for a specific |
@@ -324,7 +285,12 @@ static void ext4_end_bio(struct bio *bio, int error) | |||
324 | bi_sector >> (inode->i_blkbits - 9)); | 285 | bi_sector >> (inode->i_blkbits - 9)); |
325 | } | 286 | } |
326 | 287 | ||
327 | ext4_put_io_end_defer(io_end); | 288 | if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { |
289 | ext4_free_io_end(io_end); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | ext4_add_complete_io(io_end); | ||
328 | } | 294 | } |
329 | 295 | ||
330 | void ext4_io_submit(struct ext4_io_submit *io) | 296 | void ext4_io_submit(struct ext4_io_submit *io) |
@@ -338,37 +304,40 @@ void ext4_io_submit(struct ext4_io_submit *io) | |||
338 | bio_put(io->io_bio); | 304 | bio_put(io->io_bio); |
339 | } | 305 | } |
340 | io->io_bio = NULL; | 306 | io->io_bio = NULL; |
341 | } | 307 | io->io_op = 0; |
342 | |||
343 | void ext4_io_submit_init(struct ext4_io_submit *io, | ||
344 | struct writeback_control *wbc) | ||
345 | { | ||
346 | io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); | ||
347 | io->io_bio = NULL; | ||
348 | io->io_end = NULL; | 308 | io->io_end = NULL; |
349 | } | 309 | } |
350 | 310 | ||
351 | static int io_submit_init_bio(struct ext4_io_submit *io, | 311 | static int io_submit_init(struct ext4_io_submit *io, |
352 | struct buffer_head *bh) | 312 | struct inode *inode, |
313 | struct writeback_control *wbc, | ||
314 | struct buffer_head *bh) | ||
353 | { | 315 | { |
316 | ext4_io_end_t *io_end; | ||
317 | struct page *page = bh->b_page; | ||
354 | int nvecs = bio_get_nr_vecs(bh->b_bdev); | 318 | int nvecs = bio_get_nr_vecs(bh->b_bdev); |
355 | struct bio *bio; | 319 | struct bio *bio; |
356 | 320 | ||
321 | io_end = ext4_init_io_end(inode, GFP_NOFS); | ||
322 | if (!io_end) | ||
323 | return -ENOMEM; | ||
357 | bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); | 324 | bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); |
358 | bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); | 325 | bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); |
359 | bio->bi_bdev = bh->b_bdev; | 326 | bio->bi_bdev = bh->b_bdev; |
327 | bio->bi_private = io->io_end = io_end; | ||
360 | bio->bi_end_io = ext4_end_bio; | 328 | bio->bi_end_io = ext4_end_bio; |
361 | bio->bi_private = ext4_get_io_end(io->io_end); | 329 | |
362 | if (!io->io_end->size) | 330 | io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh); |
363 | io->io_end->offset = (bh->b_page->index << PAGE_CACHE_SHIFT) | 331 | |
364 | + bh_offset(bh); | ||
365 | io->io_bio = bio; | 332 | io->io_bio = bio; |
333 | io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); | ||
366 | io->io_next_block = bh->b_blocknr; | 334 | io->io_next_block = bh->b_blocknr; |
367 | return 0; | 335 | return 0; |
368 | } | 336 | } |
369 | 337 | ||
370 | static int io_submit_add_bh(struct ext4_io_submit *io, | 338 | static int io_submit_add_bh(struct ext4_io_submit *io, |
371 | struct inode *inode, | 339 | struct inode *inode, |
340 | struct writeback_control *wbc, | ||
372 | struct buffer_head *bh) | 341 | struct buffer_head *bh) |
373 | { | 342 | { |
374 | ext4_io_end_t *io_end; | 343 | ext4_io_end_t *io_end; |
@@ -379,18 +348,18 @@ submit_and_retry: | |||
379 | ext4_io_submit(io); | 348 | ext4_io_submit(io); |
380 | } | 349 | } |
381 | if (io->io_bio == NULL) { | 350 | if (io->io_bio == NULL) { |
382 | ret = io_submit_init_bio(io, bh); | 351 | ret = io_submit_init(io, inode, wbc, bh); |
383 | if (ret) | 352 | if (ret) |
384 | return ret; | 353 | return ret; |
385 | } | 354 | } |
386 | ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh)); | ||
387 | if (ret != bh->b_size) | ||
388 | goto submit_and_retry; | ||
389 | io_end = io->io_end; | 355 | io_end = io->io_end; |
390 | if (test_clear_buffer_uninit(bh)) | 356 | if (test_clear_buffer_uninit(bh)) |
391 | ext4_set_io_unwritten_flag(inode, io_end); | 357 | ext4_set_io_unwritten_flag(inode, io_end); |
392 | io_end->size += bh->b_size; | 358 | io->io_end->size += bh->b_size; |
393 | io->io_next_block++; | 359 | io->io_next_block++; |
360 | ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh)); | ||
361 | if (ret != bh->b_size) | ||
362 | goto submit_and_retry; | ||
394 | return 0; | 363 | return 0; |
395 | } | 364 | } |
396 | 365 | ||
@@ -462,7 +431,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
462 | do { | 431 | do { |
463 | if (!buffer_async_write(bh)) | 432 | if (!buffer_async_write(bh)) |
464 | continue; | 433 | continue; |
465 | ret = io_submit_add_bh(io, inode, bh); | 434 | ret = io_submit_add_bh(io, inode, wbc, bh); |
466 | if (ret) { | 435 | if (ret) { |
467 | /* | 436 | /* |
468 | * We only get here on ENOMEM. Not much else | 437 | * We only get here on ENOMEM. Not much else |